chore: Refactor models:

- Delete min_checked_amount and use check_amount instead
- Use Bytes and not Address in interfaces
- Move router_address from Solution to Order
This commit is contained in:
Diana Carvalho
2025-01-14 10:37:06 +00:00
parent 5d79da44f3
commit 647f697ea2
6 changed files with 69 additions and 86 deletions

View File

@@ -20,8 +20,8 @@ impl TokenApprovalsManager {
pub async fn approval_needed( pub async fn approval_needed(
&self, &self,
token: Bytes, token: Bytes,
spender_address: Address, spender_address: Bytes,
router_address: Address, router_address: Bytes,
) -> bool { ) -> bool {
// should be something like // should be something like
// let allowance = self // let allowance = self

View File

@@ -1,17 +1,18 @@
use alloy_primitives::Address; use lazy_static::lazy_static;
use num_bigint::BigUint; use num_bigint::BigUint;
use std::env;
use std::str::FromStr;
use tycho_core::{dto::ProtocolComponent, Bytes}; use tycho_core::{dto::ProtocolComponent, Bytes};
lazy_static! {
pub static ref PROPELLER_ROUTER_ADDRESS: Bytes = Bytes::from_str(
&env::var("ROUTER_ADDRESS").expect("Missing ROUTER_ADDRESS in environment"),
)
.expect("Invalid ROUTER_ADDRESS");
}
pub struct Solution { pub struct Solution {
pub orders: Vec<Order>, pub orders: Vec<Order>,
// if not set, then the Propeller Router will be used
pub router_address: Option<Address>,
}
#[derive(Clone)]
pub enum NativeAction {
Wrap,
Unwrap,
} }
pub struct Order { pub struct Order {
@@ -24,7 +25,7 @@ pub struct Order {
/// The token being bought (exact in) or sold (exact out). /// The token being bought (exact in) or sold (exact out).
checked_token: Bytes, checked_token: Bytes,
/// Amount of the checked token. /// Amount of the checked token.
checked_amount: BigUint, pub check_amount: BigUint,
/// Address of the sender. /// Address of the sender.
pub sender: Bytes, pub sender: Bytes,
/// Address of the receiver. /// Address of the receiver.
@@ -33,12 +34,20 @@ pub struct Order {
pub swaps: Vec<Swap>, pub swaps: Vec<Swap>,
/// Whether to include router calldata (true) or just swap data (false). /// Whether to include router calldata (true) or just swap data (false).
add_router_calldata: bool, add_router_calldata: bool,
// if not set, then the Propeller Router will be used
pub slippage: f64, pub router_address: Option<Bytes>,
pub min_checked_amount: Option<BigUint>, // if set, it will be applied to check_amount
pub slippage: Option<f64>,
// if set, the corresponding native action will be executed
pub native_action: Option<NativeAction>, pub native_action: Option<NativeAction>,
} }
#[derive(Clone)]
pub enum NativeAction {
Wrap,
Unwrap,
}
#[derive(Clone)] #[derive(Clone)]
pub struct Swap { pub struct Swap {
/// Protocol component from tycho indexer /// Protocol component from tycho indexer
@@ -51,12 +60,10 @@ pub struct Swap {
pub split: f64, pub split: f64,
} }
// maybe this struct is useful - keeping it here for now (maybe we could collapse this with another
// struct)
pub struct EncodingContext { pub struct EncodingContext {
pub receiver: Address, pub receiver: Bytes,
pub exact_out: bool, pub exact_out: bool,
pub router_address: Address, pub router_address: Bytes,
} }
pub enum ActionType { pub enum ActionType {

View File

@@ -7,17 +7,17 @@ pub struct PermitRequest {
pub token: Bytes, pub token: Bytes,
pub amount: BigUint, pub amount: BigUint,
pub spender: Bytes, pub spender: Bytes,
pub router_address: Address, pub router_address: Bytes,
} }
pub struct Permit2 { pub struct Permit2 {
pub address: Address, pub address: Bytes,
} }
impl Permit2 { impl Permit2 {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
address: Address::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3") address: Bytes::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3")
.expect("Permit2 address not valid"), .expect("Permit2 address not valid"),
} }
} }
@@ -33,9 +33,9 @@ impl Permit2 {
fn get_allowance_data( fn get_allowance_data(
&self, &self,
user: Address, user: Bytes,
router_address: Address, router_address: Bytes,
token: Address, token: Bytes,
) -> (U256, u64, U256) { ) -> (U256, u64, U256) {
// get allowance data (if it exists) and the nonce // get allowance data (if it exists) and the nonce
// returns permitAmount, expiration, nonce // returns permitAmount, expiration, nonce

View File

@@ -1,44 +1,24 @@
use crate::encoding::models::{Order, Solution}; use crate::encoding::models::{Order, Solution, PROPELLER_ROUTER_ADDRESS};
use crate::encoding::permit2::{Permit2, PermitRequest}; use crate::encoding::permit2::{Permit2, PermitRequest};
use crate::encoding::strategy_encoder::{ use crate::encoding::strategy_encoder::{
SequentialExactInStrategyEncoder, SingleSwapStrategyEncoder, SlipSwapStrategyEncoder, SequentialExactInStrategyEncoder, SingleSwapStrategyEncoder, SlipSwapStrategyEncoder,
StrategyEncoder, StrategyEncoder,
}; };
use crate::encoding::utils::{encode_input, ple_encode}; use crate::encoding::utils::{encode_input, ple_encode};
use alloy_primitives::Address;
use alloy_sol_types::SolValue; use alloy_sol_types::SolValue;
use anyhow::Error; use anyhow::Error;
use std::env;
use std::str::FromStr; use std::str::FromStr;
struct RouterEncoder { struct RouterEncoder {}
router_address: Address,
}
impl RouterEncoder { impl RouterEncoder {
pub fn new() -> Self {
let router_address = Address::from_str(
&env::var("ROUTER_ADDRESS").expect("Missing ROUTER_ADDRESS in environment"),
)
.expect("Invalid ROUTER_ADDRESS");
Self { router_address }
}
pub fn encode_router_calldata(&self, solution: Solution) -> Result<Vec<u8>, Error> { pub fn encode_router_calldata(&self, solution: Solution) -> Result<Vec<u8>, Error> {
let permit_calldata = self.handle_approvals(&solution)?; // TODO: where should we append this? let permit_calldata = self.handle_approvals(&solution)?; // TODO: where should we append this?
let mut calldata_list: Vec<Vec<u8>> = Vec::new(); let mut calldata_list: Vec<Vec<u8>> = Vec::new();
let encode_for_batch_execute = solution.orders.len() > 1; let encode_for_batch_execute = solution.orders.len() > 1;
for order in solution.orders { for order in solution.orders {
let strategy = self.get_strategy(&order); let strategy = self.get_strategy(&order);
let contract_interaction = strategy.encode_strategy( let contract_interaction = strategy.encode_strategy(order, encode_for_batch_execute)?;
order,
if solution.router_address.is_some() {
solution.router_address.unwrap()
} else {
self.router_address
},
encode_for_batch_execute,
)?;
calldata_list.push(contract_interaction); calldata_list.push(contract_interaction);
} }
if encode_for_batch_execute { if encode_for_batch_execute {
@@ -56,7 +36,10 @@ impl RouterEncoder {
token: order.given_token.clone(), token: order.given_token.clone(),
spender: order.sender.clone(), spender: order.sender.clone(),
amount: order.given_amount.clone(), amount: order.given_amount.clone(),
router_address: solution.router_address.unwrap_or(self.router_address), router_address: order
.router_address
.clone()
.unwrap_or(PROPELLER_ROUTER_ADDRESS.clone()),
}); });
} }
Ok(Permit2::new().encode_permit(permits)) Ok(Permit2::new().encode_permit(permits))

View File

@@ -4,7 +4,9 @@ use anyhow::Error;
use num_bigint::BigUint; use num_bigint::BigUint;
use std::cmp::min; use std::cmp::min;
use crate::encoding::models::{ActionType, EncodingContext, NativeAction, Order}; use crate::encoding::models::{
ActionType, EncodingContext, NativeAction, Order, PROPELLER_ROUTER_ADDRESS,
};
use crate::encoding::swap_encoder::{get_swap_encoder, get_swap_executor_address}; use crate::encoding::swap_encoder::{get_swap_encoder, get_swap_executor_address};
use crate::encoding::utils::{biguint_to_u256, bytes_to_address, encode_input, ple_encode}; use crate::encoding::utils::{biguint_to_u256, bytes_to_address, encode_input, ple_encode};
@@ -12,7 +14,6 @@ pub trait StrategyEncoder {
fn encode_strategy( fn encode_strategy(
&self, &self,
to_encode: Order, to_encode: Order,
router_address: Address,
encode_for_batch_execute: bool, encode_for_batch_execute: bool,
) -> Result<Vec<u8>, Error>; ) -> Result<Vec<u8>, Error>;
@@ -37,7 +38,6 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
fn encode_strategy( fn encode_strategy(
&self, &self,
order: Order, order: Order,
router_address: Address,
encode_for_batch_execute: bool, encode_for_batch_execute: bool,
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
todo!() todo!()
@@ -50,29 +50,31 @@ impl StrategyEncoder for SequentialExactInStrategyEncoder {
fn encode_strategy( fn encode_strategy(
&self, &self,
order: Order, order: Order,
router_address: Address,
encode_for_batch_execute: bool, encode_for_batch_execute: bool,
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
let mut check_amount = order.check_amount.clone();
if order.slippage.is_some() {
let one_hundred = BigUint::from(100u32); let one_hundred = BigUint::from(100u32);
let slippage_percent = BigUint::from((order.slippage * 100.0) as u32); let slippage_percent = BigUint::from((order.slippage.unwrap() * 100.0) as u32);
let multiplier = &one_hundred - slippage_percent; let multiplier = &one_hundred - slippage_percent;
let slippage_buy_amount = (&order.given_amount * multiplier) / one_hundred; check_amount = (&order.check_amount * multiplier) / one_hundred;
}
let min_checked_amount = if order.min_checked_amount.is_some() {
min(order.min_checked_amount.unwrap(), slippage_buy_amount)
} else {
slippage_buy_amount
};
let mut swaps = vec![]; let mut swaps = vec![];
for (index, swap) in order.swaps.iter().enumerate() { for (index, swap) in order.swaps.iter().enumerate() {
let is_last = index == order.swaps.len() - 1; let is_last = index == order.swaps.len() - 1;
let protocol_system = swap.component.protocol_system.clone(); let protocol_system = swap.component.protocol_system.clone();
let swap_encoder = get_swap_encoder(&protocol_system); let swap_encoder = get_swap_encoder(&protocol_system);
let receiver = if is_last { let router_address = if order.router_address.is_some() {
bytes_to_address(&order.receiver)? order.router_address.clone().unwrap()
} else { } else {
router_address PROPELLER_ROUTER_ADDRESS.clone()
}; };
let receiver = if is_last {
order.receiver.clone()
} else {
router_address.clone()
};
let encoding_context = EncodingContext { let encoding_context = EncodingContext {
receiver, receiver,
exact_out: order.exact_out, exact_out: order.exact_out,
@@ -82,17 +84,10 @@ impl StrategyEncoder for SequentialExactInStrategyEncoder {
let swap_data = self.encode_protocol_header(protocol_data, protocol_system, 0, 0, 0); let swap_data = self.encode_protocol_header(protocol_data, protocol_system, 0, 0, 0);
swaps.push(swap_data); swaps.push(swap_data);
} }
let (selector, action_type) = if order.exact_out {
( let selector = "sequentialExactIn(uint256, uint256, bytes[])";
"sequentialExactOut(uint256, uint256, bytes[])", let action_type = ActionType::SequentialExactIn;
ActionType::SequentialExactOut,
)
} else {
(
"sequentialExactIn(uint256, uint256, bytes[])",
ActionType::SequentialExactIn,
)
};
let encoded_swaps = ple_encode(swaps); let encoded_swaps = ple_encode(swaps);
let (mut unwrap, mut wrap) = (false, false); let (mut unwrap, mut wrap) = (false, false);
@@ -106,7 +101,7 @@ impl StrategyEncoder for SequentialExactInStrategyEncoder {
wrap, wrap,
unwrap, unwrap,
biguint_to_u256(&order.given_amount), biguint_to_u256(&order.given_amount),
biguint_to_u256(&min_checked_amount), biguint_to_u256(&check_amount),
encoded_swaps, encoded_swaps,
) )
.abi_encode(); .abi_encode();
@@ -125,7 +120,6 @@ impl StrategyEncoder for SlipSwapStrategyEncoder {
fn encode_strategy( fn encode_strategy(
&self, &self,
order: Order, order: Order,
router_address: Address,
encode_for_batch_execute: bool, encode_for_batch_execute: bool,
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
todo!() todo!()

View File

@@ -2,6 +2,7 @@ use alloy_primitives::Address;
use alloy_sol_types::SolValue; use alloy_sol_types::SolValue;
use anyhow::Error; use anyhow::Error;
use std::str::FromStr; use std::str::FromStr;
use tycho_core::Bytes;
use crate::encoding::utils::bytes_to_address; use crate::encoding::utils::bytes_to_address;
use crate::encoding::{ use crate::encoding::{
@@ -22,16 +23,14 @@ impl SwapEncoder for UniswapV2SwapEncoder {
} }
struct BalancerV2SwapEncoder { struct BalancerV2SwapEncoder {
vault_address: Option<Address>, vault_address: Bytes,
} }
impl BalancerV2SwapEncoder { impl BalancerV2SwapEncoder {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
vault_address: Some( vault_address: Bytes::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8")
Address::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8")
.expect("Invalid string for balancer vault address"), .expect("Invalid string for balancer vault address"),
),
} }
} }
} }
@@ -49,7 +48,7 @@ impl SwapEncoder for BalancerV2SwapEncoder {
.approval_needed( .approval_needed(
swap.token_in.clone(), swap.token_in.clone(),
encoding_context.router_address, encoding_context.router_address,
self.vault_address.unwrap(), self.vault_address.clone(),
) )
.await .await
}); });
@@ -59,7 +58,7 @@ impl SwapEncoder for BalancerV2SwapEncoder {
bytes_to_address(&swap.token_in)?, bytes_to_address(&swap.token_in)?,
bytes_to_address(&swap.token_out)?, bytes_to_address(&swap.token_out)?,
swap.component.id, swap.component.id,
encoding_context.receiver, bytes_to_address(&encoding_context.receiver)?,
encoding_context.exact_out, encoding_context.exact_out,
approval_needed, approval_needed,
); );