Skip to content

Commit

Permalink
Revert "Update ethcontract-rs version (#2644)"
Browse files Browse the repository at this point in the history
This reverts commit 98e13ae.
  • Loading branch information
MartinquaXD committed May 22, 2024
1 parent 74ffcc1 commit 4b927bd
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 41 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ chrono = { version = "0.4.38", default-features = false }
clap = { version = "4.5.4", features = ["derive", "env"] }
derivative = "2.2.0"
derive_more = "0.99.17"
ethcontract = { version = "0.25.6", default-features = false, features = ["aws-kms"] }
ethcontract-generate = { version = "0.25.6", default-features = false }
ethcontract-mock = { version = "0.25.6", default-features = false }
ethcontract = { version = "=0.25.5", default-features = false, features = ["aws-kms"] }
ethcontract-generate = { version = "=0.25.5", default-features = false }
ethcontract-mock = { version = "=0.25.5", default-features = false }
ethereum-types = "0.14.1"
flate2 = "1.0.28"
futures = "0.3.30"
Expand Down
1 change: 0 additions & 1 deletion crates/autopilot/src/decoded_settlement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ impl DecodedSettlement {

pub fn new(input: &[u8], domain_separator: &DomainSeparator) -> Result<Self, DecodingError> {
let function = GPv2Settlement::raw_contract()
.interface
.abi
.function("settle")
.unwrap();
Expand Down
1 change: 0 additions & 1 deletion crates/autopilot/src/domain/settlement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ impl Settlement {
domain_separator: &eth::DomainSeparator,
) -> Result<Self, Error> {
let function = contracts::GPv2Settlement::raw_contract()
.interface
.abi
.function("settle")
.unwrap();
Expand Down
191 changes: 191 additions & 0 deletions crates/autopilot/src/domain/settlement/solution/tokenized.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use {
crate::{
boundary,
domain::{
self,
auction::{self, order},
eth,
},
},
app_data::AppDataHash,
ethcontract::{common::FunctionExt, tokens::Tokenize, Address, Bytes, U256},
};

// Original type for input of `GPv2Settlement.settle` function.
pub(super) struct Tokenized {
pub tokens: Vec<Address>,
pub clearing_prices: Vec<U256>,
pub trades: Vec<Trade>,
pub interactions: [Vec<Interaction>; 3],
pub auction_id: auction::Id,
}

impl Tokenized {
/// Number of bytes that may be appended to the calldata to store an auction
/// id.
const META_DATA_LEN: usize = 8;

pub fn new(calldata: &eth::Calldata) -> Result<Self, error::Decoding> {
let function = contracts::GPv2Settlement::raw_contract()
.abi
.function("settle")
.unwrap();
let data = calldata
.0
.strip_prefix(&function.selector())
.ok_or(error::Decoding::InvalidSelector)?;

let (calldata, metadata) = data.split_at(data.len() - Self::META_DATA_LEN);
let metadata: Option<[u8; Self::META_DATA_LEN]> = metadata.try_into().ok();
let auction_id = metadata
.map(auction::Id::from_be_bytes)
.ok_or(error::Decoding::MissingAuctionId)?;

let tokenized = function
.decode_input(calldata)
.map_err(|err| error::Decoding::Ethabi(err, auction_id))?;
let (tokens, clearing_prices, trades, interactions) =
<Solution>::from_token(web3::ethabi::Token::Tuple(tokenized))
.map_err(|err| error::Decoding::Tokenizing(err, auction_id))?;
Ok(Self {
tokens,
clearing_prices,
trades,
interactions,
auction_id,
})
}
}

type Token = Address;
type Trade = (
U256, // sellTokenIndex
U256, // buyTokenIndex
Address, // receiver
U256, // sellAmount
U256, // buyAmount
u32, // validTo
Bytes<[u8; 32]>, // appData
U256, // feeAmount
U256, // flags
U256, // executedAmount
Bytes<Vec<u8>>, // signature
);
type Interaction = (Address, U256, Bytes<Vec<u8>>);
type Solution = (Vec<Address>, Vec<U256>, Vec<Trade>, [Vec<Interaction>; 3]);

/// Recover order uid from order data and signature
pub fn order_uid(
trade: &Trade,
tokens: &[Token],
domain_separator: &eth::DomainSeparator,
) -> Result<domain::OrderUid, error::Uid> {
let flags = TradeFlags(trade.8);
let signature = crate::boundary::Signature::from_bytes(flags.signing_scheme(), &trade.10 .0)
.map_err(error::Uid::Signature)?;

let order = model::order::OrderData {
sell_token: tokens[trade.0.as_u64() as usize],
buy_token: tokens[trade.1.as_u64() as usize],
receiver: Some(trade.2),
sell_amount: trade.3,
buy_amount: trade.4,
valid_to: trade.5,
app_data: AppDataHash(trade.6 .0),
fee_amount: trade.7,
kind: match flags.side() {
domain::auction::order::Side::Buy => model::order::OrderKind::Buy,
domain::auction::order::Side::Sell => model::order::OrderKind::Sell,
},
partially_fillable: flags.partially_fillable(),
sell_token_balance: flags.sell_token_balance(),
buy_token_balance: flags.buy_token_balance(),
};
let domain_separator = crate::boundary::DomainSeparator(domain_separator.0);
let owner = signature
.recover_owner(&trade.10 .0, &domain_separator, &order.hash_struct())
.map_err(error::Uid::RecoverOwner)?;
Ok(order.uid(&domain_separator, &owner).into())
}

/// Trade flags are encoded in a 256-bit integer field. For more information on
/// how flags are encoded see:
/// <https://github.com/cowprotocol/contracts/blob/v1.0.0/src/contracts/libraries/GPv2Trade.sol#L58-L94>
#[derive(Debug, PartialEq, Eq)]
pub struct TradeFlags(pub U256);

impl TradeFlags {
fn as_u8(&self) -> u8 {
self.0.byte(0)
}

pub fn side(&self) -> order::Side {
if self.as_u8() & 0b1 == 0 {
order::Side::Sell
} else {
order::Side::Buy
}
}

pub fn partially_fillable(&self) -> bool {
self.as_u8() & 0b10 != 0
}

pub fn sell_token_balance(&self) -> boundary::SellTokenSource {
if self.as_u8() & 0x08 == 0 {
boundary::SellTokenSource::Erc20
} else if self.as_u8() & 0x04 == 0 {
boundary::SellTokenSource::External
} else {
boundary::SellTokenSource::Internal
}
}

pub fn buy_token_balance(&self) -> boundary::BuyTokenDestination {
if self.as_u8() & 0x10 == 0 {
boundary::BuyTokenDestination::Erc20
} else {
boundary::BuyTokenDestination::Internal
}
}

pub fn signing_scheme(&self) -> boundary::SigningScheme {
match (self.as_u8() >> 5) & 0b11 {
0b00 => boundary::SigningScheme::Eip712,
0b01 => boundary::SigningScheme::EthSign,
0b10 => boundary::SigningScheme::Eip1271,
0b11 => boundary::SigningScheme::PreSign,
_ => unreachable!(),
}
}
}

impl From<U256> for TradeFlags {
fn from(value: U256) -> Self {
Self(value)
}
}

pub mod error {
use crate::domain::auction;

#[derive(Debug, thiserror::Error)]
pub enum Uid {
#[error("bad signature {0}")]
Signature(anyhow::Error),
#[error("recover owner {0}")]
RecoverOwner(anyhow::Error),
}

#[derive(Debug, thiserror::Error)]
pub enum Decoding {
#[error("transaction calldata is not a settlement")]
InvalidSelector,
#[error("no auction id found in calldata")]
MissingAuctionId,
#[error("unable to decode settlement calldata: {0}")]
Ethabi(web3::ethabi::Error, auction::Id),
#[error("unable to tokenize calldata into expected format: {0}")]
Tokenizing(ethcontract::tokens::Error, auction::Id),
}
}
6 changes: 1 addition & 5 deletions crates/contracts/src/vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ use {
};

fn role_id(target: H160, function_name: &str) -> Bytes<[u8; 32]> {
let function = match BalancerV2Vault::raw_contract()
.interface
.abi
.function(function_name)
{
let function = match BalancerV2Vault::raw_contract().abi.function(function_name) {
Ok(function) => function,
Err(_) => return Bytes([0u8; 32]),
};
Expand Down
6 changes: 1 addition & 5 deletions crates/shared/src/price_estimation/trade_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,11 +464,7 @@ struct SettleOutput {

impl SettleOutput {
fn decode(output: &[u8], kind: OrderKind) -> Result<Self> {
let function = Solver::raw_contract()
.interface
.abi
.function("swap")
.unwrap();
let function = Solver::raw_contract().abi.function("swap").unwrap();
let tokens = function.decode_output(output).context("decode")?;
let (gas_used, balances): (U256, Vec<U256>) = Tokenize::from_token(Token::Tuple(tokens))?;

Expand Down
Loading

0 comments on commit 4b927bd

Please sign in to comment.