feat: ApprovalsManager trait
Make Permit2 and TokenApprovalsManager implement it. This way in the RouternEncoder we can use either one (I'm not exactly sure what this would mean in the contract though) I'm not sure I like this generalisation. The TokenApprovalsManager was made with a different purpose: to approve token allowances for the pools (like balancer and curve) for our router
This commit is contained in:
@@ -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<RootProvider<BoxTransport>>,
|
||||
}
|
||||
|
||||
impl TokenApprovalsManager {
|
||||
pub fn new(client: Arc<RootProvider<BoxTransport>>) -> 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<Approval>) -> Vec<u8> {
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
13
src/encoding/approvals/interface.rs
Normal file
13
src/encoding/approvals/interface.rs
Normal file
@@ -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<Approval>) -> Vec<u8>;
|
||||
}
|
||||
3
src/encoding/approvals/mod.rs
Normal file
3
src/encoding/approvals/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub(crate) mod approvals_manager;
|
||||
pub(crate) mod interface;
|
||||
mod permit2;
|
||||
@@ -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<PermitRequest>) -> Vec<u8> {
|
||||
// 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<Approval>) -> Vec<u8> {
|
||||
// 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!()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
mod approvals_manager;
|
||||
mod approvals;
|
||||
mod models;
|
||||
mod permit2;
|
||||
mod router_encoder;
|
||||
mod strategy_encoder;
|
||||
mod strategy_selector;
|
||||
|
||||
@@ -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<S: StrategySelector> {
|
||||
struct RouterEncoder<S: StrategySelector, A: ApprovalsManager> {
|
||||
strategy_selector: S,
|
||||
approvals_manager: A,
|
||||
}
|
||||
impl<S: StrategySelector> RouterEncoder<S> {
|
||||
pub fn new(strategy_selector: S) -> Self {
|
||||
RouterEncoder { strategy_selector }
|
||||
impl<S: StrategySelector, A: ApprovalsManager> RouterEncoder<S, A> {
|
||||
pub fn new(strategy_selector: S, approvals_manager: A) -> Self {
|
||||
RouterEncoder {
|
||||
strategy_selector,
|
||||
approvals_manager,
|
||||
}
|
||||
}
|
||||
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 approvals_calldata = self.handle_approvals(&solution)?; // TODO: where should we append this?
|
||||
let mut calldata_list: Vec<Vec<u8>> = Vec::new();
|
||||
let encode_for_batch_execute = solution.orders.len() > 1;
|
||||
for order in solution.orders {
|
||||
@@ -31,18 +35,18 @@ impl<S: StrategySelector> RouterEncoder<S> {
|
||||
}
|
||||
|
||||
fn handle_approvals(&self, solution: &Solution) -> Result<Vec<u8>, 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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Vec<u8>, Error>;
|
||||
}
|
||||
@@ -37,19 +38,19 @@ impl BalancerV2SwapEncoder {
|
||||
|
||||
impl SwapEncoder for BalancerV2SwapEncoder {
|
||||
fn encode_swap(&self, swap: Swap, encoding_context: EncodingContext) -> Result<Vec<u8>, 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
|
||||
|
||||
Reference in New Issue
Block a user