feat(contract): use u64 and add more chains to multicall (#2042)

* feat: add new chains and use u64

* chore: manually implement Clone and Debug to avoid trait bounds.

Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
DaniPopes 2023-01-13 19:18:55 +01:00 committed by GitHub
parent 9e559aefeb
commit 5edcd3765c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 92 additions and 71 deletions

View File

@ -1,13 +1,11 @@
use crate::{ use crate::call::{ContractCall, ContractError};
call::{ContractCall, ContractError},
Lazy,
};
use ethers_core::{ use ethers_core::{
abi::{AbiDecode, Detokenize, Function, Token}, abi::{AbiDecode, Detokenize, Function, Token},
types::{Address, BlockNumber, Bytes, Chain, NameOrAddress, H160, U256}, types::{Address, BlockNumber, Bytes, Chain, NameOrAddress, H160, U256},
}; };
use ethers_providers::{Middleware, PendingTransaction}; use ethers_providers::{Middleware, PendingTransaction};
use std::{convert::TryFrom, sync::Arc}; use std::{convert::TryFrom, fmt, sync::Arc};
pub mod multicall_contract; pub mod multicall_contract;
use multicall_contract::multicall_3::{ use multicall_contract::multicall_3::{
@ -26,60 +24,70 @@ pub const MULTICALL_ADDRESS: Address = H160([
]); ]);
/// The chain IDs that [`MULTICALL_ADDRESS`] has been deployed to. /// The chain IDs that [`MULTICALL_ADDRESS`] has been deployed to.
///
/// Taken from: <https://github.com/mds1/multicall#multicall3-contract-addresses> /// Taken from: <https://github.com/mds1/multicall#multicall3-contract-addresses>
pub static MULTICALL_SUPPORTED_CHAIN_IDS: Lazy<[U256; 48]> = Lazy::new(|| { pub const MULTICALL_SUPPORTED_CHAIN_IDS: &[u64] = {
use Chain::*; use Chain::*;
[ &[
U256::from(Mainnet), // Mainnet Mainnet as u64, // Mainnet
U256::from(Kovan), // Kovan Kovan as u64, // Kovan
U256::from(Rinkeby), // Rinkeby Rinkeby as u64, // Rinkeby
U256::from(Goerli), // Goerli Goerli as u64, // Görli
U256::from(Ropsten), // Ropsten Ropsten as u64, // Ropsten
U256::from(Sepolia), // Sepolia Sepolia as u64, // Sepolia
U256::from(Optimism), // Optimism Optimism as u64, // Optimism
U256::from(OptimismGoerli), // OptimismGoerli OptimismKovan as u64, // Optimism Kovan
U256::from(OptimismKovan), // OptimismKovan OptimismGoerli as u64, // Optimism Görli
U256::from(Arbitrum), // Arbitrum Arbitrum as u64, // Arbitrum
U256::from(ArbitrumGoerli), // ArbitrumGoerli, ArbitrumNova as u64, // Arbitrum Nova
U256::from(ArbitrumTestnet), // Arbitrum Rinkeby ArbitrumGoerli as u64, // Arbitrum Görli
U256::from(Polygon), // Polygon ArbitrumTestnet as u64, // Arbitrum Rinkeby
U256::from(PolygonMumbai), // PolygonMumbai Polygon as u64, // Polygon
U256::from(XDai), // XDai PolygonMumbai as u64, // Polygon Mumbai
U256::from(Chiado), // ChiadoTestnet XDai as u64, // Gnosis Chain
U256::from(Avalanche), // Avalanche Avalanche as u64, // Avalanche
U256::from(AvalancheFuji), // AvalancheFuji AvalancheFuji as u64, // Avalanche Fuji
U256::from(FantomTestnet), // FantomTestnet FantomTestnet as u64, // Fantom Testnet
U256::from(Fantom), // Fantom Fantom as u64, // Fantom Opera
U256::from(BinanceSmartChain), // BinanceSmartChain BinanceSmartChain as u64, // BNB Smart Chain
U256::from(BinanceSmartChainTestnet), // BinanceSmartChainTestnet BinanceSmartChainTestnet as u64, // BNB Smart Chain Testnet
U256::from(Moonbeam), // Moonbeam Moonbeam as u64, // Moonbeam
U256::from(Moonriver), // Moonriver Moonriver as u64, // Moonriver
U256::from(Moonbase), // Moonbase Moonbase as u64, // Moonbase
U256::from(1666600000), // Harmony0 1666600000, // Harmony0
U256::from(1666600001), // Harmony1 1666600001, // Harmony1
U256::from(1666600002), // Harmony2 1666600002, // Harmony2
U256::from(1666600003), // Harmony3 1666600003, // Harmony3
U256::from(Cronos), // Cronos Cronos as u64, // Cronos
U256::from(122), // Fuse 122, // Fuse
U256::from(19), // Songbird 14, // Flare Mainnet
U256::from(16), // CostonTestnet 19, // Songbird Canary Network
U256::from(288), // Boba 16, // Coston Testnet
U256::from(Aurora), // Aurora 114, // Coston2 Testnet
U256::from(592), // Astar 288, // Boba
U256::from(66), // OKC Aurora as u64, // Aurora
U256::from(128), // Heco 592, // Astar
U256::from(1088), // Metis 66, // OKC
U256::from(Rsk), // Rsk 128, // Heco Chain
U256::from(31), // RskTestnet 1088, // Metis
U256::from(Evmos), // Evmos Rsk as u64, // Rsk
U256::from(EvmosTestnet), // EvmosTestnet 31, // Rsk Testnet
U256::from(71402), // Godwoken Evmos as u64, // Evmos
U256::from(71401), // GodwokenTestnet EvmosTestnet as u64, // Evmos Testnet
U256::from(8217), // Klaytn Oasis as u64, // Oasis
U256::from(2001), // Milkomeda 42261, // Oasis Emerald ParaTime Testnet
U256::from(321), // KCC 42262, // Oasis Emerald ParaTime
Celo as u64, // Celo
CeloAlfajores as u64, // Celo Alfajores Testnet
71402, // Godwoken
71401, // Godwoken Testnet
8217, // Klaytn
2001, // Milkomeda
321, // KCC
106, // Velas
40, // Telos
] ]
}); };
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum MulticallError<M: Middleware> { pub enum MulticallError<M: Middleware> {
@ -87,7 +95,7 @@ pub enum MulticallError<M: Middleware> {
ContractError(#[from] ContractError<M>), ContractError(#[from] ContractError<M>),
#[error("Chain ID {0} is currently not supported by Multicall. Provide an address instead.")] #[error("Chain ID {0} is currently not supported by Multicall. Provide an address instead.")]
InvalidChainId(U256), InvalidChainId(u64),
#[error("Illegal revert: Multicall2 call reverted when it wasn't allowed to.")] #[error("Illegal revert: Multicall2 call reverted when it wasn't allowed to.")]
IllegalRevert, IllegalRevert,
@ -257,7 +265,6 @@ impl TryFrom<u8> for MulticallVersion {
/// [`add_call`]: #method.add_call /// [`add_call`]: #method.add_call
/// [`call`]: #method.call /// [`call`]: #method.call
/// [`send`]: #method.send /// [`send`]: #method.send
#[derive(Clone)]
#[must_use = "Multicall does nothing unless you use `call` or `send`"] #[must_use = "Multicall does nothing unless you use `call` or `send`"]
pub struct Multicall<M> { pub struct Multicall<M> {
/// The Multicall contract interface. /// The Multicall contract interface.
@ -268,15 +275,27 @@ pub struct Multicall<M> {
calls: Vec<Call>, calls: Vec<Call>,
} }
// Manually implement Debug due to Middleware trait bounds. // Manually implement Clone and Debug to avoid trait bounds.
impl<M: Middleware> std::fmt::Debug for Multicall<M> { impl<M> Clone for Multicall<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn clone(&self) -> Self {
Self {
contract: self.contract.clone(),
version: self.version,
legacy: self.legacy,
block: self.block.clone(),
calls: self.calls.clone(),
}
}
}
impl<M> fmt::Debug for Multicall<M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Multicall") f.debug_struct("Multicall")
.field("address", &self.contract.address())
.field("version", &self.version) .field("version", &self.version)
.field("legacy", &self.legacy) .field("legacy", &self.legacy)
.field("block", &self.block) .field("block", &self.block)
.field("calls", &self.calls) .field("calls", &self.calls)
.field("contract", &self.contract)
.finish() .finish()
} }
} }
@ -305,7 +324,7 @@ impl<M: Middleware> Multicall<M> {
Some(addr) => addr, Some(addr) => addr,
None => { None => {
let chain_id = let chain_id =
client.get_chainid().await.map_err(ContractError::MiddlewareError)?; client.get_chainid().await.map_err(ContractError::MiddlewareError)?.as_u64();
if !MULTICALL_SUPPORTED_CHAIN_IDS.contains(&chain_id) { if !MULTICALL_SUPPORTED_CHAIN_IDS.contains(&chain_id) {
return Err(MulticallError::InvalidChainId(chain_id)) return Err(MulticallError::InvalidChainId(chain_id))
} }
@ -341,22 +360,24 @@ impl<M: Middleware> Multicall<M> {
pub fn new_with_chain_id( pub fn new_with_chain_id(
client: impl Into<Arc<M>>, client: impl Into<Arc<M>>,
address: Option<Address>, address: Option<Address>,
chain_id: Option<impl Into<U256>>, chain_id: Option<impl Into<u64>>,
) -> Result<Self, M> { ) -> Result<Self, M> {
// If no address is provided, check if chain_id is supported and use the default multicall // If no address is provided, check if chain_id is supported and use the default multicall
// address. // address.
let address: Address = match address { let address: Address = match (address, chain_id) {
Some(addr) => addr, (Some(addr), _) => addr,
None => { (_, Some(chain_id)) => {
// Can't fetch chain_id from provider since we're not in an async function so we let chain_id = chain_id.into();
// panic instead.
let chain_id =
chain_id.expect("Must provide at least one of: address or chain ID.").into();
if !MULTICALL_SUPPORTED_CHAIN_IDS.contains(&chain_id) { if !MULTICALL_SUPPORTED_CHAIN_IDS.contains(&chain_id) {
return Err(MulticallError::InvalidChainId(chain_id)) return Err(MulticallError::InvalidChainId(chain_id))
} }
MULTICALL_ADDRESS MULTICALL_ADDRESS
} }
_ => {
// Can't fetch chain_id from provider since we're not in an async function so we
// panic instead.
panic!("Must provide at least one of: address or chain ID.")
}
}; };
// Instantiate the multicall contract // Instantiate the multicall contract