From 12f121dc4212c59d1ae55c847d5d4129a5760482 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Fri, 18 Oct 2024 21:40:17 +0200 Subject: [PATCH 1/2] Convert ETH to WETH --- crates/autopilot/src/domain/eth/mod.rs | 27 +++++++++++++++++++ .../src/infra/blockchain/contracts.rs | 4 +++ crates/autopilot/src/run_loop.rs | 5 +++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/crates/autopilot/src/domain/eth/mod.rs b/crates/autopilot/src/domain/eth/mod.rs index 8ea6975af6..57fefe3e68 100644 --- a/crates/autopilot/src/domain/eth/mod.rs +++ b/crates/autopilot/src/domain/eth/mod.rs @@ -4,6 +4,12 @@ use { derive_more::{Display, From, Into}, }; +/// ERC20 token address for ETH. In reality, ETH is not an ERC20 token because +/// it does not implement the ERC20 interface, but this address is used by +/// convention across the Ethereum ecosystem whenever ETH is treated like an +/// ERC20 token. +pub const ETH_TOKEN: TokenAddress = TokenAddress(H160([0xee; 20])); + /// An address. Can be an EOA or a smart contract address. #[derive( Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, Display, @@ -33,6 +39,27 @@ pub struct TxId(pub H256); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into)] pub struct TokenAddress(pub H160); +impl TokenAddress { + /// If the token is ETH, return WETH, thereby "wrapping" it. + pub fn wrap(self, weth: WethAddress) -> Self { + if self == ETH_TOKEN { + weth.into() + } else { + self + } + } +} + +/// The address of the WETH contract. +#[derive(Debug, Clone, Copy, From, Into)] +pub struct WethAddress(pub TokenAddress); + +impl From for WethAddress { + fn from(value: H160) -> Self { + WethAddress(value.into()) + } +} + /// An ERC20 token amount. /// /// https://eips.ethereum.org/EIPS/eip-20 diff --git a/crates/autopilot/src/infra/blockchain/contracts.rs b/crates/autopilot/src/infra/blockchain/contracts.rs index 95304db9ad..697ba62afd 100644 --- a/crates/autopilot/src/infra/blockchain/contracts.rs +++ b/crates/autopilot/src/infra/blockchain/contracts.rs @@ -89,6 +89,10 @@ impl Contracts { &self.weth } + pub fn weth_address(&self) -> domain::eth::WethAddress { + self.weth.address().into() + } + pub fn authenticator(&self) -> &contracts::GPv2AllowListAuthentication { &self.authenticator } diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index a761362595..603e52b86d 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -573,6 +573,7 @@ impl RunLoop { // until `max_winners_per_auction` are selected. The solution is a winner // if it swaps tokens that are not yet swapped by any other already // selected winner. + let weth = self.eth.contracts().weth_address(); let mut already_swapped_tokens = HashSet::new(); let mut winners = 0; let solutions = solutions @@ -582,7 +583,9 @@ impl RunLoop { .solution() .orders() .iter() - .flat_map(|(_, order)| [order.sell.token, order.buy.token]) + .flat_map(|(_, order)| { + [order.sell.token.wrap(weth), order.buy.token.wrap(weth)] + }) .collect::>(); let is_winner = swapped_tokens.is_disjoint(&already_swapped_tokens) From a8c188e2a1542884f76c1677dbcf617ec2474ed8 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Tue, 22 Oct 2024 15:23:00 +0200 Subject: [PATCH 2/2] Renaming to wrapped native token --- crates/autopilot/src/domain/eth/mod.rs | 21 +++++++++++-------- .../src/infra/blockchain/contracts.rs | 4 +++- crates/autopilot/src/run_loop.rs | 6 +++--- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/crates/autopilot/src/domain/eth/mod.rs b/crates/autopilot/src/domain/eth/mod.rs index b83285169d..9b187526ba 100644 --- a/crates/autopilot/src/domain/eth/mod.rs +++ b/crates/autopilot/src/domain/eth/mod.rs @@ -8,7 +8,8 @@ use { /// it does not implement the ERC20 interface, but this address is used by /// convention across the Ethereum ecosystem whenever ETH is treated like an /// ERC20 token. -pub const ETH_TOKEN: TokenAddress = TokenAddress(H160([0xee; 20])); +/// Same address is also used for XDAI on Gnosis Chain. +pub const NATIVE_TOKEN: TokenAddress = TokenAddress(H160([0xee; 20])); /// An address. Can be an EOA or a smart contract address. #[derive( @@ -40,23 +41,25 @@ pub struct TxId(pub H256); pub struct TokenAddress(pub H160); impl TokenAddress { - /// If the token is ETH, return WETH, thereby converting it to erc20. - pub fn as_erc20(self, weth: WethAddress) -> Self { - if self == ETH_TOKEN { - weth.into() + /// If the token is ETH/XDAI, return WETH/WXDAI, thereby converting it to + /// erc20. + pub fn as_erc20(self, wrapped: WrappedNativeToken) -> Self { + if self == NATIVE_TOKEN { + wrapped.into() } else { self } } } -/// The address of the WETH contract. +/// ERC20 representation of the chain's native token (e.g. WETH on mainnet, +/// WXDAI on Gnosis Chain). #[derive(Debug, Clone, Copy, From, Into)] -pub struct WethAddress(TokenAddress); +pub struct WrappedNativeToken(TokenAddress); -impl From for WethAddress { +impl From for WrappedNativeToken { fn from(value: H160) -> Self { - WethAddress(value.into()) + WrappedNativeToken(value.into()) } } diff --git a/crates/autopilot/src/infra/blockchain/contracts.rs b/crates/autopilot/src/infra/blockchain/contracts.rs index 697ba62afd..0db3f67a66 100644 --- a/crates/autopilot/src/infra/blockchain/contracts.rs +++ b/crates/autopilot/src/infra/blockchain/contracts.rs @@ -89,7 +89,9 @@ impl Contracts { &self.weth } - pub fn weth_address(&self) -> domain::eth::WethAddress { + /// Wrapped version of the native token (e.g. WETH for Ethereum, WXDAI for + /// Gnosis Chain) + pub fn wrapped_native_token(&self) -> domain::eth::WrappedNativeToken { self.weth.address().into() } diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index c659946dc6..fab0ac5ceb 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -566,7 +566,7 @@ impl RunLoop { // until `max_winners_per_auction` are selected. The solution is a winner // if it swaps tokens that are not yet swapped by any previously processed // solution. - let weth = self.eth.contracts().weth_address(); + let wrapped_native_token = self.eth.contracts().wrapped_native_token(); let mut already_swapped_tokens = HashSet::new(); let mut winners = 0; let solutions = solutions @@ -578,8 +578,8 @@ impl RunLoop { .iter() .flat_map(|(_, order)| { [ - order.sell.token.as_erc20(weth), - order.buy.token.as_erc20(weth), + order.sell.token.as_erc20(wrapped_native_token), + order.buy.token.as_erc20(wrapped_native_token), ] }) .collect::>();