feat(contract): add extra Multicall helper methods (#1666)
* feat(contract): add extra Multicall helper methods * docs: update CHANGELOG.md * normalize helper methods' names
This commit is contained in:
parent
4e1462423f
commit
72449c09e1
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
||||||
- Fix RLP encoding of `TransactionReceipt`
|
- Fix RLP encoding of `TransactionReceipt` [#1661](https://github.com/gakonst/ethers-rs/pull/1661)
|
||||||
- Add `Unit8` helper type [#1639](https://github.com/gakonst/ethers-rs/pull/1639)
|
- Add `Unit8` helper type [#1639](https://github.com/gakonst/ethers-rs/pull/1639)
|
||||||
- Add `evm.deployedBytecode.immutableReferences` output selector [#1523](https://github.com/gakonst/ethers-rs/pull/1523)
|
- Add `evm.deployedBytecode.immutableReferences` output selector [#1523](https://github.com/gakonst/ethers-rs/pull/1523)
|
||||||
- Added `get_erc1155_token_transfer_events` function for etherscan client [#1503](https://github.com/gakonst/ethers-rs/pull/1503)
|
- Added `get_erc1155_token_transfer_events` function for etherscan client [#1503](https://github.com/gakonst/ethers-rs/pull/1503)
|
||||||
|
@ -263,6 +263,10 @@
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
||||||
|
- Add extra Multicall helper methods
|
||||||
|
[#1666](https://github.com/gakonst/ethers-rs/pull/1666)
|
||||||
|
- Update Multicall to Multicall3
|
||||||
|
[#1584](https://github.com/gakonst/ethers-rs/pull/1584)
|
||||||
- Add `Event::stream_with_meta` and `Event::subscribe_with_meta`
|
- Add `Event::stream_with_meta` and `Event::subscribe_with_meta`
|
||||||
[#1483](https://github.com/gakonst/ethers-rs/pull/1483)
|
[#1483](https://github.com/gakonst/ethers-rs/pull/1483)
|
||||||
- Added tx builder methods to `ContractFactory`
|
- Added tx builder methods to `ContractFactory`
|
||||||
|
|
|
@ -96,6 +96,17 @@ pub enum MulticallError<M: Middleware> {
|
||||||
|
|
||||||
pub type Result<T, M> = std::result::Result<T, MulticallError<M>>;
|
pub type Result<T, M> = std::result::Result<T, MulticallError<M>>;
|
||||||
|
|
||||||
|
/// Helper struct for managing calls to be made to the `function` in smart contract `target`
|
||||||
|
/// with `data`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Call {
|
||||||
|
target: Address,
|
||||||
|
data: Bytes,
|
||||||
|
value: U256,
|
||||||
|
allow_failure: bool,
|
||||||
|
function: Function,
|
||||||
|
}
|
||||||
|
|
||||||
/// The version of the [`Multicall`](super::Multicall).
|
/// The version of the [`Multicall`](super::Multicall).
|
||||||
/// Used to determine which methods of the Multicall smart contract to use:
|
/// Used to determine which methods of the Multicall smart contract to use:
|
||||||
/// - [`Multicall`] : `aggregate((address,bytes)[])`
|
/// - [`Multicall`] : `aggregate((address,bytes)[])`
|
||||||
|
@ -224,16 +235,16 @@ impl TryFrom<u8> for MulticallVersion {
|
||||||
/// multicall = multicall.version(MulticallVersion::Multicall);
|
/// multicall = multicall.version(MulticallVersion::Multicall);
|
||||||
/// multicall
|
/// multicall
|
||||||
/// .clear_calls()
|
/// .clear_calls()
|
||||||
/// .eth_balance_of(address_1, false)
|
/// .add_get_eth_balance(address_1, false)
|
||||||
/// .eth_balance_of(address_2, false);
|
/// .add_get_eth_balance(address_2, false);
|
||||||
/// let _balances: (U256, U256) = multicall.call().await?;
|
/// let _balances: (U256, U256) = multicall.call().await?;
|
||||||
///
|
///
|
||||||
/// // or with version 2 and above
|
/// // or with version 2 and above
|
||||||
/// multicall = multicall.version(MulticallVersion::Multicall3);
|
/// multicall = multicall.version(MulticallVersion::Multicall3);
|
||||||
/// multicall
|
/// multicall
|
||||||
/// .clear_calls()
|
/// .clear_calls()
|
||||||
/// .eth_balance_of(address_1, false)
|
/// .add_get_eth_balance(address_1, false)
|
||||||
/// .eth_balance_of(address_2, false);
|
/// .add_get_eth_balance(address_2, false);
|
||||||
/// let _balances: ((bool, U256), (bool, U256)) = multicall.call().await?;
|
/// let _balances: ((bool, U256), (bool, U256)) = multicall.call().await?;
|
||||||
///
|
///
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
|
@ -248,6 +259,7 @@ 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> {
|
||||||
version: MulticallVersion,
|
version: MulticallVersion,
|
||||||
|
@ -257,18 +269,7 @@ pub struct Multicall<M> {
|
||||||
contract: MulticallContract<M>,
|
contract: MulticallContract<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> Clone for Multicall<M> {
|
// Manually implement Debug due to Middleware trait bounds.
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Multicall {
|
|
||||||
calls: self.calls.clone(),
|
|
||||||
block: self.block,
|
|
||||||
contract: self.contract.clone(),
|
|
||||||
legacy: self.legacy,
|
|
||||||
version: self.version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: Middleware> std::fmt::Debug for Multicall<M> {
|
impl<M: Middleware> std::fmt::Debug for Multicall<M> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("Multicall")
|
f.debug_struct("Multicall")
|
||||||
|
@ -281,17 +282,6 @@ impl<M: Middleware> std::fmt::Debug for Multicall<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper struct for managing calls to be made to the `function` in smart contract `target`
|
|
||||||
/// with `data`.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Call {
|
|
||||||
target: Address,
|
|
||||||
data: Bytes,
|
|
||||||
value: U256,
|
|
||||||
allow_failure: bool,
|
|
||||||
function: Function,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: Middleware> Multicall<M> {
|
impl<M: Middleware> Multicall<M> {
|
||||||
/// Creates a new Multicall instance from the provided client. If provided with an `address`,
|
/// Creates a new Multicall instance from the provided client. If provided with an `address`,
|
||||||
/// it instantiates the Multicall contract with that address, otherwise it defaults to
|
/// it instantiates the Multicall contract with that address, otherwise it defaults to
|
||||||
|
@ -410,13 +400,13 @@ impl<M: Middleware> Multicall<M> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the `block` field for the multicall aggregate call.
|
/// Sets the `block` field of the Multicall aggregate call.
|
||||||
pub fn block(mut self, block: impl Into<BlockNumber>) -> Self {
|
pub fn block(mut self, block: impl Into<BlockNumber>) -> Self {
|
||||||
self.block = Some(block.into());
|
self.block = Some(block.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a `call` to the list of calls for the Multicall instance.
|
/// Appends a `call` to the list of calls of the Multicall instance.
|
||||||
///
|
///
|
||||||
/// Version specific details:
|
/// Version specific details:
|
||||||
/// - 1: `allow_failure` is ignored.
|
/// - 1: `allow_failure` is ignored.
|
||||||
|
@ -447,18 +437,89 @@ impl<M: Middleware> Multicall<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a `call` to the list of calls for the Multicall instance for querying
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the block hash
|
||||||
/// the ETH balance of an address
|
/// of a given block number.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// Note: this call will return 0 if `block_number` is not one of the most recent 256 blocks.
|
||||||
|
/// ([Reference](https://docs.soliditylang.org/en/latest/units-and-global-variables.html?highlight=blockhash#block-and-transaction-properties))
|
||||||
|
pub fn add_get_block_hash(&mut self, block_number: impl Into<U256>) -> &mut Self {
|
||||||
|
let call = self.contract.get_block_hash(block_number.into());
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the current
|
||||||
|
/// block number.
|
||||||
|
pub fn add_get_block_number(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_block_number();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the current
|
||||||
|
/// block coinbase address.
|
||||||
|
pub fn add_get_current_block_coinbase(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_current_block_coinbase();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the current
|
||||||
|
/// block difficulty.
|
||||||
///
|
///
|
||||||
/// If more than the maximum number of supported calls are added (16). The maximum limit is
|
/// Note: in a post-merge environment, the return value of this call will be the output of the
|
||||||
/// constrained due to tokenization/detokenization support for tuples.
|
/// randomness beacon provided by the beacon chain.
|
||||||
pub fn eth_balance_of(&mut self, addr: Address, allow_failure: bool) -> &mut Self {
|
/// ([Reference](https://eips.ethereum.org/EIPS/eip-4399#abstract))
|
||||||
let call = self.contract.get_eth_balance(addr);
|
pub fn add_get_current_block_difficulty(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_current_block_difficulty();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the current
|
||||||
|
/// block gas limit.
|
||||||
|
pub fn add_get_current_block_gas_limit(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_current_block_gas_limit();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the current
|
||||||
|
/// block timestamp.
|
||||||
|
pub fn add_get_current_block_timestamp(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_current_block_timestamp();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the ETH
|
||||||
|
/// balance of an address.
|
||||||
|
pub fn add_get_eth_balance(
|
||||||
|
&mut self,
|
||||||
|
address: impl Into<Address>,
|
||||||
|
allow_failure: bool,
|
||||||
|
) -> &mut Self {
|
||||||
|
let call = self.contract.get_eth_balance(address.into());
|
||||||
self.add_call(call, allow_failure)
|
self.add_call(call, allow_failure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the last
|
||||||
|
/// block hash.
|
||||||
|
pub fn add_get_last_block_hash(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_last_block_hash();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the current
|
||||||
|
/// block base fee.
|
||||||
|
///
|
||||||
|
/// Note: this call will fail if the chain that it is called on does not implement the
|
||||||
|
/// [BASEFEE opcode](https://eips.ethereum.org/EIPS/eip-3198).
|
||||||
|
pub fn add_get_basefee(&mut self, allow_failure: bool) -> &mut Self {
|
||||||
|
let call = self.contract.get_basefee();
|
||||||
|
self.add_call(call, allow_failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a `call` to the list of calls of the Multicall instance for querying the chain id.
|
||||||
|
pub fn add_get_chain_id(&mut self) -> &mut Self {
|
||||||
|
let call = self.contract.get_chain_id();
|
||||||
|
self.add_call(call, false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Clears the batch of calls from the Multicall instance.
|
/// Clears the batch of calls from the Multicall instance.
|
||||||
/// Re-use the already instantiated Multicall to send a different batch of transactions or do
|
/// Re-use the already instantiated Multicall to send a different batch of transactions or do
|
||||||
/// another aggregate query.
|
/// another aggregate query.
|
||||||
|
|
|
@ -499,9 +499,9 @@ mod eth_tests {
|
||||||
// so should have 100 ETH
|
// so should have 100 ETH
|
||||||
multicall
|
multicall
|
||||||
.clear_calls()
|
.clear_calls()
|
||||||
.eth_balance_of(addrs[4], false)
|
.add_get_eth_balance(addrs[4], false)
|
||||||
.eth_balance_of(addrs[5], false)
|
.add_get_eth_balance(addrs[5], false)
|
||||||
.eth_balance_of(addrs[6], false);
|
.add_get_eth_balance(addrs[6], false);
|
||||||
|
|
||||||
let balances: (U256, U256, U256) = multicall.call().await.unwrap();
|
let balances: (U256, U256, U256) = multicall.call().await.unwrap();
|
||||||
assert_eq!(balances.0, U256::from(10_000_000_000_000_000_000_000u128));
|
assert_eq!(balances.0, U256::from(10_000_000_000_000_000_000_000u128));
|
||||||
|
@ -653,8 +653,8 @@ mod eth_tests {
|
||||||
// ((bool, U256)) == (bool, U256)
|
// ((bool, U256)) == (bool, U256)
|
||||||
let bal_before: ((bool, U256), (bool, U256)) = multicall
|
let bal_before: ((bool, U256), (bool, U256)) = multicall
|
||||||
.clear_calls()
|
.clear_calls()
|
||||||
.eth_balance_of(rc_addr, false)
|
.add_get_eth_balance(rc_addr, false)
|
||||||
.eth_balance_of(rc_addr, false)
|
.add_get_eth_balance(rc_addr, false)
|
||||||
.call()
|
.call()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -665,8 +665,8 @@ mod eth_tests {
|
||||||
|
|
||||||
let bal_after: ((bool, U256), (bool, U256)) = multicall
|
let bal_after: ((bool, U256), (bool, U256)) = multicall
|
||||||
.clear_calls()
|
.clear_calls()
|
||||||
.eth_balance_of(rc_addr, false)
|
.add_get_eth_balance(rc_addr, false)
|
||||||
.eth_balance_of(rc_addr, false)
|
.add_get_eth_balance(rc_addr, false)
|
||||||
.call()
|
.call()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
Loading…
Reference in New Issue