diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index 538b893..5cbe4b8 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -1,5 +1,6 @@ mod approvals_manager; mod models; +mod permit2; mod router_encoder; mod strategy_encoder; mod swap_encoder; diff --git a/src/encoding/models.rs b/src/encoding/models.rs index 5086ca4..bb35846 100644 --- a/src/encoding/models.rs +++ b/src/encoding/models.rs @@ -18,7 +18,7 @@ pub struct Order { /// True if the order is an exact output order. pub exact_out: bool, /// The token being sold (exact in) or bought (exact out). - given_token: Bytes, + pub given_token: Bytes, /// Amount of the given token. pub given_amount: BigUint, /// The token being bought (exact in) or sold (exact out). @@ -26,7 +26,7 @@ pub struct Order { /// Amount of the checked token. checked_amount: BigUint, /// Address of the sender. - sender: Bytes, + pub sender: Bytes, /// Address of the receiver. pub receiver: Bytes, /// List of swaps to fulfill the order. diff --git a/src/encoding/permit2.rs b/src/encoding/permit2.rs new file mode 100644 index 0000000..d76ba27 --- /dev/null +++ b/src/encoding/permit2.rs @@ -0,0 +1,44 @@ +use alloy_primitives::{Address, U256}; +use num_bigint::BigUint; +use std::str::FromStr; +use tycho_core::Bytes; + +pub struct PermitRequest { + pub token: Bytes, + pub amount: BigUint, + pub spender: Bytes, + pub router_address: Address, +} + +pub struct Permit2 { + pub address: Address, +} + +impl Permit2 { + pub fn new() -> Self { + Self { + address: Address::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3") + .expect("Permit2 address not valid"), + } + } + pub fn encode_permit(&self, details: Vec) -> Vec { + // calls get_allowance_data to get nonce + // checks if we are not permitted already + // puts data into a permitSingle struct if there is only 1 PermitDetails, if there are several, use PermitBatch + // adds the nonce and the expiration (uniswap recommends 30 days for expiration) + // signs data + // returns encoded data + todo!() + } + + fn get_allowance_data( + &self, + user: Address, + router_address: Address, + token: Address, + ) -> (U256, u64, U256) { + // get allowance data (if it exists) and the nonce + // returns permitAmount, expiration, nonce + todo!() + } +} diff --git a/src/encoding/router_encoder.rs b/src/encoding/router_encoder.rs index 011d100..abdcbf8 100644 --- a/src/encoding/router_encoder.rs +++ b/src/encoding/router_encoder.rs @@ -1,4 +1,5 @@ use crate::encoding::models::{Order, Solution}; +use crate::encoding::permit2::{Permit2, PermitRequest}; use crate::encoding::strategy_encoder::{ SequentialExactInStrategyEncoder, SingleSwapStrategyEncoder, SlipSwapStrategyEncoder, StrategyEncoder, @@ -24,6 +25,7 @@ impl RouterEncoder { } pub fn encode_router_calldata(&self, solution: Solution) -> Result, Error> { + let permit_calldata = self.handle_approvals(&solution)?; // TODO: where should we append this? let mut calldata_list: Vec> = Vec::new(); let encode_for_batch_execute = solution.orders.len() > 1; for order in solution.orders { @@ -47,6 +49,19 @@ impl RouterEncoder { } } + fn handle_approvals(&self, solution: &Solution) -> Result, Error> { + let mut permits = Vec::new(); + for order in solution.orders.iter() { + permits.push(PermitRequest { + token: order.given_token.clone(), + spender: order.sender.clone(), + amount: order.given_amount.clone(), + router_address: solution.router_address.unwrap_or(self.router_address), + }); + } + Ok(Permit2::new().encode_permit(permits)) + } + fn get_strategy(&self, order: &Order) -> &dyn StrategyEncoder { if order.swaps.len() == 1 { &SingleSwapStrategyEncoder {}