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:
parent
9e559aefeb
commit
5edcd3765c
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue