Skip to content

Commit

Permalink
Remove boundary encoding for quotes (#2704)
Browse files Browse the repository at this point in the history
# Description
I noticed that we are also using boundary encoding when generating
quotes. This should also be done in the domain

# Changes
- [x] Expose methods to encode approvals and protocol provided liquidity
- [x] Replicate boundary quote encoding logic in domain
- [x] Add new error type in case quote encoding fails

## How to test
Existing unit tests.
  • Loading branch information
fleupold authored May 10, 2024
1 parent 16629c9 commit d8b01fc
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 79 deletions.
1 change: 0 additions & 1 deletion crates/driver/src/boundary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
//! Software (2014)
pub mod liquidity;
pub mod quote;
pub mod settlement;

// The [`anyhow::Error`] type is re-exported because the legacy code mostly
Expand Down
74 changes: 0 additions & 74 deletions crates/driver/src/boundary/quote.rs

This file was deleted.

4 changes: 2 additions & 2 deletions crates/driver/src/domain/competition/solution/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ pub fn tx(
})
}

fn liquidity_interaction(
pub fn liquidity_interaction(
liquidity: &Liquidity,
slippage: &slippage::Parameters,
settlement: &contracts::GPv2Settlement,
Expand Down Expand Up @@ -261,7 +261,7 @@ fn liquidity_interaction(
.ok_or(Error::InvalidInteractionExecution(liquidity.clone()))
}

fn approve(allowance: &Allowance) -> eth::Interaction {
pub fn approve(allowance: &Allowance) -> eth::Interaction {
let mut amount = [0u8; 32];
let selector = hex_literal::hex!("095ea7b3");
allowance.amount.to_big_endian(&mut amount);
Expand Down
8 changes: 8 additions & 0 deletions crates/driver/src/domain/eth/allowance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,12 @@ impl Approval {
..self.0
})
}

/// Revoke the approval, i.e. set the approved amount to [`U256::zero`].
pub fn revoke(self) -> Self {
Self(Allowance {
amount: U256::zero(),
..self.0
})
}
}
73 changes: 71 additions & 2 deletions crates/driver/src/domain/quote.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use {
super::competition::auction,
super::competition::{auction, solution},
crate::{
boundary,
domain::{
Expand Down Expand Up @@ -58,7 +58,14 @@ impl Quote {

Ok(Self {
amount: eth::U256::from_big_rational(&amount)?,
interactions: boundary::quote::encode_interactions(eth, solution.interactions())?,
interactions: solution
.interactions()
.iter()
.map(|i| encode::interaction(i, eth.contracts().settlement()))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.collect(),
solver: solution.solver().address(),
gas: solution.gas(),
tx_origin: *solution.solver().quote_tx_origin(),
Expand Down Expand Up @@ -258,6 +265,66 @@ impl Tokens {
}
}

mod encode {
use {
crate::domain::{
competition::solution,
eth::{
self,
allowance::{Approval, Required},
},
},
num::rational::Ratio,
};

const DEFAULT_QUOTE_SLIPPAGE_BPS: u32 = 100;

pub(super) fn interaction(
interaction: &solution::Interaction,
settlement: &contracts::GPv2Settlement,
) -> Result<Vec<eth::Interaction>, solution::encoding::Error> {
let slippage = solution::slippage::Parameters {
relative: Ratio::new_raw(DEFAULT_QUOTE_SLIPPAGE_BPS.into(), 10_000.into()),
max: None,
min: None,
prices: Default::default(),
};

let encoded = match interaction {
solution::Interaction::Custom(interaction) => eth::Interaction {
value: interaction.value,
target: interaction.target.0.into(),
call_data: interaction.call_data.clone(),
},
solution::Interaction::Liquidity(liquidity) => {
solution::encoding::liquidity_interaction(liquidity, &slippage, settlement)?
}
};

Ok(interaction
.allowances()
.iter()
.flat_map(|Required(allowance)| {
let approval = Approval(*allowance);
// When encoding approvals for quotes, reset the allowance instead
// of just setting it. This is required as some tokens only allow
// you to approve a non-0 value if the allowance was 0 to begin
// with, such as Tether USD.
//
// Alternatively, we could check existing allowances and only encode
// the approvals if needed, but this would only result in small gas
// optimizations which is mostly inconsequential for quotes and not
// worth the performance hit.
vec![
solution::encoding::approve(&approval.revoke().0),
solution::encoding::approve(&approval.max().0),
]
})
.chain(std::iter::once(encoded))
.collect())
}
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
/// This can happen e.g. if there's no available liquidity for the tokens
Expand All @@ -273,6 +340,8 @@ pub enum Error {
Solver(#[from] solver::Error),
#[error("boundary error: {0:?}")]
Boundary(#[from] boundary::Error),
#[error("encoding error: {0:?}")]
Encoding(#[from] solution::encoding::Error),
}

#[derive(Debug, thiserror::Error)]
Expand Down
1 change: 1 addition & 0 deletions crates/driver/src/infra/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ impl From<quote::Error> for (hyper::StatusCode, axum::Json<Error>) {
quote::Error::Solver(_) => Kind::SolverFailed,
quote::Error::Blockchain(_) => Kind::Unknown,
quote::Error::Boundary(_) => Kind::Unknown,
quote::Error::Encoding(_) => Kind::Unknown,
};
error.into()
}
Expand Down
1 change: 1 addition & 0 deletions crates/driver/src/infra/observe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ pub fn quoted(solver: &solver::Name, order: &quote::Order, result: &Result<Quote
}
quote::Error::Solver(solver::Error::Dto(_)) => "SolverDtoError",
quote::Error::Boundary(_) => "Unknown",
quote::Error::Encoding(_) => "Encoding",
},
])
.inc();
Expand Down

0 comments on commit d8b01fc

Please sign in to comment.