Skip to content

Commit

Permalink
Add univ3-router solver
Browse files Browse the repository at this point in the history
  • Loading branch information
vkgnosis committed Apr 14, 2022
1 parent ad8b329 commit 3a2b060
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 1 deletion.
2 changes: 2 additions & 0 deletions crates/shared/src/univ3_router_api.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Bindings for an instance of https://github.com/cowprotocol/univ3-api .

use crate::solver_utils::deserialize_prefixed_hex;
use anyhow::{Context, Result};
use model::u256_decimal;
Expand Down
1 change: 0 additions & 1 deletion crates/solver/src/settlement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ pub trait Interaction: std::fmt::Debug + Send + Sync {
fn encode(&self) -> Vec<EncodedInteraction>;
}

#[cfg(test)]
impl Interaction for EncodedInteraction {
fn encode(&self) -> Vec<EncodedInteraction> {
vec![self.clone()]
Expand Down
1 change: 1 addition & 0 deletions crates/solver/src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod naive_solver;
mod oneinch_solver;
mod paraswap_solver;
mod single_order_solver;
pub mod univ3_router_solver;
mod zeroex_solver;

/// Interface that all solvers must implement.
Expand Down
151 changes: 151 additions & 0 deletions crates/solver/src/solver/univ3_router_solver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use super::{
single_order_solver::{execution_respects_order, SettlementError, SingleOrderSolving},
Auction,
};
use crate::{
encoding::EncodedInteraction,
interactions::allowances::{AllowanceManager, AllowanceManaging, ApprovalRequest},
liquidity::LimitOrder,
settlement::Settlement,
};
use ethcontract::{Account, Bytes};
use model::order::OrderKind;
use primitive_types::{H160, U256};
use shared::{addr, univ3_router_api, Web3};

pub struct Univ3RouterSolver {
api: univ3_router_api::Api,
settlement_contract: H160,
swap_router_02: H160,
account: Account,
allowance: AllowanceManager,
}

impl Univ3RouterSolver {
pub fn new(
api: univ3_router_api::Api,
web3: Web3,
settlement_contract: H160,
account: Account,
) -> Self {
Self {
api,
settlement_contract,
// https://docs.uniswap.org/protocol/reference/deployments
swap_router_02: addr!("68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"),
account,
allowance: AllowanceManager::new(web3, settlement_contract),
}
}
}

#[async_trait::async_trait]
impl SingleOrderSolving for Univ3RouterSolver {
async fn try_settle_order(
&self,
order: LimitOrder,
_: &Auction,
) -> Result<Option<Settlement>, SettlementError> {
let request = univ3_router_api::Request {
type_: match order.kind {
OrderKind::Buy => univ3_router_api::Type::Buy,
OrderKind::Sell => univ3_router_api::Type::Sell,
},
token_in: order.sell_token,
token_out: order.buy_token,
amount: match order.kind {
OrderKind::Buy => order.buy_amount,
OrderKind::Sell => order.sell_amount,
},
recipient: self.settlement_contract,
};
tracing::debug!(?request);
let response = self.api.request(&request).await?;
tracing::debug!(?response);
let (executed_buy_amount, executed_sell_amount) = match order.kind {
OrderKind::Buy => (order.buy_amount, response.quote),
OrderKind::Sell => (response.quote, order.sell_amount),
};
if !execution_respects_order(&order, executed_sell_amount, executed_buy_amount) {
tracing::debug!("does not respect limit price");
return Ok(None);
}
let prices = [
(order.buy_token, executed_buy_amount),
(order.sell_token, executed_sell_amount),
];
let mut settlement = Settlement::new(prices.into_iter().collect());
settlement.with_liquidity(&order, order.full_execution_amount())?;
let approval = self
.allowance
.get_approval(&ApprovalRequest {
token: order.sell_token,
spender: self.swap_router_02,
amount: order.sell_amount,
})
.await?;
settlement.encoder.append_to_execution_plan(approval);
let interaction: EncodedInteraction = (
self.swap_router_02,
U256::from(0u32),
Bytes(response.call_data),
);
settlement.encoder.append_to_execution_plan(interaction);
Ok(Some(settlement))
}

fn account(&self) -> &Account {
&self.account
}

fn name(&self) -> &'static str {
"Univ3Router"
}
}

#[cfg(test)]
mod tests {
use super::*;
use contracts::WETH9;
use model::order::{Order, OrderCreation};

#[tokio::test]
#[ignore]
async fn real() {
shared::tracing::initialize_for_tests("solver=debug");
let transport = shared::transport::create_env_test_transport();
let web3 = Web3::new(transport);
let api = univ3_router_api::Api::new(
Default::default(),
"http://localhost:8080".parse().unwrap(),
);
let settlement_contract = contracts::GPv2Settlement::deployed(&web3).await.unwrap();
let weth = WETH9::deployed(&web3).await.unwrap();
let solver = Univ3RouterSolver::new(
api,
web3,
settlement_contract.address(),
crate::test::account(),
);
let settlement = solver
.try_settle_order(
Order {
creation: OrderCreation {
sell_token: weth.address(),
buy_token: testlib::tokens::DAI,
sell_amount: U256::from_f64_lossy(1e18),
buy_amount: U256::from(1u32),
kind: OrderKind::Sell,
..Default::default()
},
..Default::default()
}
.into(),
&Auction::default(),
)
.await
.unwrap()
.unwrap();
tracing::info!("{:#?}", settlement);
}
}

0 comments on commit 3a2b060

Please sign in to comment.