diff --git a/src/encoding/approvals_manager.rs b/src/encoding/approvals/approvals_manager.rs similarity index 74% rename from src/encoding/approvals_manager.rs rename to src/encoding/approvals/approvals_manager.rs index 3747557..9ab0629 100644 --- a/src/encoding/approvals_manager.rs +++ b/src/encoding/approvals/approvals_manager.rs @@ -1,28 +1,29 @@ use std::{env, sync::Arc}; +use crate::encoding::approvals::interface::{Approval, ApprovalsManager}; use alloy::{ providers::{Provider, ProviderBuilder, RootProvider}, transports::BoxTransport, }; -use alloy_primitives::{Address, U256}; use dotenv::dotenv; -use tycho_core::Bytes; pub struct TokenApprovalsManager { client: Arc>, } - impl TokenApprovalsManager { - pub fn new(client: Arc>) -> Self { - Self { client } + pub fn new() -> Self { + Self { + client: get_client(), + } } + pub async fn approval_needed(&self, approval: Approval) -> bool { + todo!() + } +} - pub async fn approval_needed( - &self, - token: Bytes, - spender_address: Bytes, - router_address: Bytes, - ) -> bool { +impl ApprovalsManager for TokenApprovalsManager { + fn encode_approvals(&self, approvals: Vec) -> Vec { + todo!() // should be something like // let allowance = self // .client @@ -30,7 +31,6 @@ impl TokenApprovalsManager { // .await; // // allowance == U256::ZERO // If allowance is 0, approval is needed - todo!() } } diff --git a/src/encoding/approvals/interface.rs b/src/encoding/approvals/interface.rs new file mode 100644 index 0000000..9664927 --- /dev/null +++ b/src/encoding/approvals/interface.rs @@ -0,0 +1,13 @@ +use num_bigint::BigUint; +use tycho_core::Bytes; + +pub struct Approval { + pub spender: Bytes, + pub owner: Bytes, + pub token: Bytes, + pub amount: BigUint, +} + +pub trait ApprovalsManager { + fn encode_approvals(&self, approvals: Vec) -> Vec; +} diff --git a/src/encoding/approvals/mod.rs b/src/encoding/approvals/mod.rs new file mode 100644 index 0000000..8fbe120 --- /dev/null +++ b/src/encoding/approvals/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod approvals_manager; +pub(crate) mod interface; +mod permit2; diff --git a/src/encoding/permit2.rs b/src/encoding/approvals/permit2.rs similarity index 81% rename from src/encoding/permit2.rs rename to src/encoding/approvals/permit2.rs index 1a527be..4f5d9f7 100644 --- a/src/encoding/permit2.rs +++ b/src/encoding/approvals/permit2.rs @@ -1,15 +1,8 @@ +use crate::encoding::approvals::interface::{Approval, ApprovalsManager}; use alloy_primitives::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: Bytes, -} - pub struct Permit2 { pub address: Bytes, } @@ -21,16 +14,6 @@ impl Permit2 { .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: Bytes, @@ -42,3 +25,14 @@ impl Permit2 { todo!() } } +impl ApprovalsManager for Permit2 { + fn encode_approvals(&self, approvals: 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!() + } +} diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index 8631ba1..d9e8233 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -1,6 +1,5 @@ -mod approvals_manager; +mod approvals; mod models; -mod permit2; mod router_encoder; mod strategy_encoder; mod strategy_selector; diff --git a/src/encoding/router_encoder.rs b/src/encoding/router_encoder.rs index b13d083..7256e13 100644 --- a/src/encoding/router_encoder.rs +++ b/src/encoding/router_encoder.rs @@ -1,20 +1,24 @@ +use crate::encoding::approvals::interface::{Approval, ApprovalsManager}; use crate::encoding::models::{Solution, PROPELLER_ROUTER_ADDRESS}; -use crate::encoding::permit2::{Permit2, PermitRequest}; use crate::encoding::strategy_encoder::StrategyEncoder; use crate::encoding::strategy_selector::StrategySelector; use crate::encoding::utils::{encode_input, ple_encode}; use alloy_sol_types::SolValue; use anyhow::Error; -struct RouterEncoder { +struct RouterEncoder { strategy_selector: S, + approvals_manager: A, } -impl RouterEncoder { - pub fn new(strategy_selector: S) -> Self { - RouterEncoder { strategy_selector } +impl RouterEncoder { + pub fn new(strategy_selector: S, approvals_manager: A) -> Self { + RouterEncoder { + strategy_selector, + approvals_manager, + } } pub fn encode_router_calldata(&self, solution: Solution) -> Result, Error> { - let permit_calldata = self.handle_approvals(&solution)?; // TODO: where should we append this? + let approvals_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 { @@ -31,18 +35,18 @@ impl RouterEncoder { } fn handle_approvals(&self, solution: &Solution) -> Result, Error> { - let mut permits = Vec::new(); + let mut approvals = Vec::new(); for order in solution.orders.iter() { - permits.push(PermitRequest { + approvals.push(Approval { token: order.given_token.clone(), - spender: order.sender.clone(), - amount: order.given_amount.clone(), - router_address: order + spender: order .router_address .clone() .unwrap_or(PROPELLER_ROUTER_ADDRESS.clone()), + amount: order.given_amount.clone(), + owner: order.sender.clone(), }); } - Ok(Permit2::new().encode_permit(permits)) + Ok(self.approvals_manager.encode_approvals(approvals)) } } diff --git a/src/encoding/swap_encoder.rs b/src/encoding/swap_encoder.rs index 5227f5e..232d8d7 100644 --- a/src/encoding/swap_encoder.rs +++ b/src/encoding/swap_encoder.rs @@ -1,15 +1,16 @@ -use alloy_primitives::Address; +use crate::encoding::approvals::approvals_manager::TokenApprovalsManager; +use crate::encoding::approvals::interface::Approval; +use crate::encoding::approvals::interface::ApprovalsManager; +use crate::encoding::models::{EncodingContext, Swap}; +use crate::encoding::utils::bytes_to_address; +use alloy_primitives::{Address, U256}; use alloy_sol_types::SolValue; use anyhow::Error; +use num_bigint::BigUint; +use num_traits::identities::One; use std::str::FromStr; use tycho_core::Bytes; -use crate::encoding::utils::bytes_to_address; -use crate::encoding::{ - approvals_manager::{get_client, TokenApprovalsManager}, - models::{EncodingContext, Swap}, -}; - pub trait SwapEncoder: Sync + Send { fn encode_swap(&self, swap: Swap, encoding_context: EncodingContext) -> Result, Error>; } @@ -37,19 +38,19 @@ impl BalancerV2SwapEncoder { impl SwapEncoder for BalancerV2SwapEncoder { fn encode_swap(&self, swap: Swap, encoding_context: EncodingContext) -> Result, Error> { - let client = get_client(); - let token_approvals_manager = TokenApprovalsManager::new(client); + let token_approvals_manager = TokenApprovalsManager::new(); let runtime = tokio::runtime::Handle::try_current() .is_err() .then(|| tokio::runtime::Runtime::new().unwrap()) .unwrap(); let approval_needed = runtime.block_on(async { token_approvals_manager - .approval_needed( - swap.token_in.clone(), - encoding_context.router_address, - self.vault_address.clone(), - ) + .approval_needed(Approval { + spender: self.vault_address.clone(), + owner: encoding_context.router_address, + token: swap.token_in.clone(), + amount: (BigUint::one() << 256) - BigUint::one(), // max U256 + }) .await }); // should we return gas estimation here too?? if there is an approval needed, gas will be