@0xsequence/multicall 中文文档教程
@0xsequence/multicall
一个以太坊提供者包装器,将多个操作聚合在一起,减少客户端和服务器上的网络负载。 该项目旨在与现有的 ether.js 集成即插即用。
有关详细信息,请参阅 0xsequence 项目页面。
灵感来自 MakerDAO Multicall.js。
Installation
yarn add @0xsequence/multicall
或
npm install --save @0xsequence/multicall
Usage
Sequence Multicall 通过实现 ethers.Provider
并包装现有的 < code>ethers.Provider; 这个包装的提供者可以透明地聚合支持的 JSON-RPC 调用。
import { providers } from '@0xsequence/multicall'
import { providers as ethersProviders } from 'ethers'
// MulticallProvider can wrap and extend with multicall functionality
// any ethers.js provider, it's not limited to JsonRpcProvider
const provider = new providers.MulticallProvider(new ethersProviders.JsonRpcProvider("https://cloudflare-eth.com/"))
Making aggregated calls
Multicall 利用 RPC 调用的异步特性来执行聚合; 它实现了一个具有可配置的 50 毫秒延迟的缓冲区,并聚合了该窗口内接收到的所有操作。
可以通过使用 Promise.all
进行多次调用来强制显式使用该功能。
// Both requests are aggregated into a single RPC call
const [balance, supply] = await Promise.all([
provider.getBalance("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
dai.totalSupply()
])
也可以在不使用 Promise.all
的情况下聚合方法,只要调用之间没有 await
。
// DON'T
const balance = await provider.getBalance("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
const supply = await dai.totalSupply()
// DO
const balancePromise = provider.getBalance("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
const supplyPromise = dai.totalSupply()
const balance = await balancePromise
const supply = await supplyPromise
Using the provider
MulticallProvider
实例可以在任何需要 ethers.Provider 的上下文中使用,包括合约接口、中间件或库; 对同一提供者的所有调用都是聚合的候选对象。
// Uses a single JSON-RPC call
const abi = [
"function balanceOf(address owner) view returns (uint256)",
"function totalSupply() view returns (uint256)",
"function symbol() view returns (string)",
]
const uni = new ethers.Contract("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", abi, provider)
const dai = new ethers.Contract("0x6B175474E89094C44Da98b954EedeAC495271d0F", abi, provider)
const uniTotalSupplyPromise = uni.totalSupply()
const [totalSupply, balance, daiSymbol, uniSymbol] = await Promise.all([
dai.totalSupply(),
dai.balanceOf("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"),
dai.symbol(),
uni.symbol()
])
const uniTotalSupply = await uniTotalSupplyPromise
Supported methods
调用聚合支持以下 JSON-RPC 方法:
Method | Supported | Implemented | Notes |
---|---|---|---|
eth_call | Yes | Yes | Requests containing from , gasPrice or value aren't aggregated. |
eth_getBalance | Yes | Yes | |
eth_getCode | Yes | Yes | |
eth_blockNumber | Yes | No |
作为标准一部分的所有其他 RPC 方法都将转发给父提供者,无需任何修改。
⚠️ 使用混合块标签会使一些调用跳过聚合。
Error handling
multicall 包装器旨在透明地与任何现有的 ether.js 集成一起工作; 这包括对 multicall 失败、配置错误或合约不支持的情况的错误处理。
在以下任何情况下,JSON-RPC 调用将转发给父提供者:
- Multicall contract is not deployed on the given network
- Individual call fails (only failed calls are forwarded)
- Batch call fails (all calls are forwarded)
- Invalid RPC Call (invalid address, etc.)
- Mixed blocktags within a batch
- Unsupported special parameters (see supported methods)
- Unsupported method
Configuration
MulticallProvider 带有预定义的配置; 它已经准备好在网络上开箱即用:主网、Ropsten、Kovan、Rinkeby、Görli 和 Matic(主网)。
DEFAULT_CONF = {
batchSize: 50,
timeWindow: 50, // ms
contract: "0xCa731e0f33Afbcfa9363d6F7449d1f5447d10C80"
}
Parameter | Required | Description |
---|---|---|
batchSize | Yes | Defines the maximum number of calls to batch into a single JSON-RPC call. |
timeWindow | Yes | Defines the time each call is held on buffer waiting for subsequent calls before aggregation, use 0 for "next js tick". |
contract | Yes | Instance of MultiCallUtils contract, see: https://github.com/0xsequence/wallet-contracts/blob/master/src/contracts/modules/utils/MultiCallUtils.sol. |
Supported networks
公用事业合同是0xCa731e0f33Afbcfa9363d6F7449d1f5447d10C80
,它已使用Universal Deployer进行部署,并使用相同的所有网络上的地址。 它可以在任何这些链上使用而无需更改配置。
Network | Address | Deployed |
---|---|---|
Mainnet | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Ropsten | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Rinkeby | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Kovan | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Görli | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Matic | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Mumbai (Matic testnet) | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Arbitrum | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Arbitrum testnet | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
它可以部署在任何支持 CREATE2
操作码的网络上。
@0xsequence/multicall
An Ethereum provider wrapper that aggregates multiple operations in one, reducing the network load on clients and servers. The project aims to be plug-and-play with existing ether.js integrations.
For more info see 0xsequence project page.
Inspired by MakerDAO Multicall.js.
Installation
yarn add @0xsequence/multicall
or
npm install --save @0xsequence/multicall
Usage
Sequence Multicall works by implementing ethers.Provider
and wrapping an existing ethers.Provider
; this wrapped provider can transparently aggregate supported JSON-RPC calls.
import { providers } from '@0xsequence/multicall'
import { providers as ethersProviders } from 'ethers'
// MulticallProvider can wrap and extend with multicall functionality
// any ethers.js provider, it's not limited to JsonRpcProvider
const provider = new providers.MulticallProvider(new ethersProviders.JsonRpcProvider("https://cloudflare-eth.com/"))
Making aggregated calls
Multicall leverages RPC calls' asynchronous nature to perform the aggregation; it implements a buffer with a configurable 50ms delay and aggregates all operations received within that window.
Explicit usage of the functionality can be forced by making multiple calls using Promise.all
.
// Both requests are aggregated into a single RPC call
const [balance, supply] = await Promise.all([
provider.getBalance("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
dai.totalSupply()
])
Methods can also be aggregated without using Promise.all
, as long as there are no await
in between calls.
// DON'T
const balance = await provider.getBalance("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
const supply = await dai.totalSupply()
// DO
const balancePromise = provider.getBalance("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
const supplyPromise = dai.totalSupply()
const balance = await balancePromise
const supply = await supplyPromise
Using the provider
The MulticallProvider
instance can be used in any context where an ethers.Provider is expected, including contract interfaces, middlewares, or libraries; all calls to the same provider are candidates for aggregation.
// Uses a single JSON-RPC call
const abi = [
"function balanceOf(address owner) view returns (uint256)",
"function totalSupply() view returns (uint256)",
"function symbol() view returns (string)",
]
const uni = new ethers.Contract("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", abi, provider)
const dai = new ethers.Contract("0x6B175474E89094C44Da98b954EedeAC495271d0F", abi, provider)
const uniTotalSupplyPromise = uni.totalSupply()
const [totalSupply, balance, daiSymbol, uniSymbol] = await Promise.all([
dai.totalSupply(),
dai.balanceOf("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"),
dai.symbol(),
uni.symbol()
])
const uniTotalSupply = await uniTotalSupplyPromise
Supported methods
The following JSON-RPC methods are supported for call aggregation:
Method | Supported | Implemented | Notes |
---|---|---|---|
eth_call | Yes | Yes | Requests containing from , gasPrice or value aren't aggregated. |
eth_getBalance | Yes | Yes | |
eth_getCode | Yes | Yes | |
eth_blockNumber | Yes | No |
All other RPC methods that are part of the standard are forwarded to the parent provider without any modifications.
⚠️ Using mixed blocktags will make some calls skip aggregation.
Error handling
The multicall wrapper is designed to work with any exiting ether.js integration transparently; this includes error handling for cases when multicall fails, is wrongly configured, or the contract does not support it.
JSON-RPC Calls are forwarded to the parent provider on any of the following cases:
- Multicall contract is not deployed on the given network
- Individual call fails (only failed calls are forwarded)
- Batch call fails (all calls are forwarded)
- Invalid RPC Call (invalid address, etc.)
- Mixed blocktags within a batch
- Unsupported special parameters (see supported methods)
- Unsupported method
Configuration
The MulticallProvider comes with a pre-defined configuration; it's ready to work out-of-the-box on the networks: Mainnet, Ropsten, Kovan, Rinkeby, Görli, and Matic (Mainnet).
DEFAULT_CONF = {
batchSize: 50,
timeWindow: 50, // ms
contract: "0xCa731e0f33Afbcfa9363d6F7449d1f5447d10C80"
}
Parameter | Required | Description |
---|---|---|
batchSize | Yes | Defines the maximum number of calls to batch into a single JSON-RPC call. |
timeWindow | Yes | Defines the time each call is held on buffer waiting for subsequent calls before aggregation, use 0 for "next js tick". |
contract | Yes | Instance of MultiCallUtils contract, see: https://github.com/0xsequence/wallet-contracts/blob/master/src/contracts/modules/utils/MultiCallUtils.sol. |
Supported networks
The utility contract is 0xCa731e0f33Afbcfa9363d6F7449d1f5447d10C80
, it has been deployed using an Universal Deployer and it uses the same address on all networks. It can be used on any of these chains without configuration changes.
Network | Address | Deployed |
---|---|---|
Mainnet | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Ropsten | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Rinkeby | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Kovan | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Görli | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Matic | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Mumbai (Matic testnet) | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Arbitrum | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
Arbitrum testnet | 0xd130B43062D875a4B7aF3f8fc036Bc6e9D3E1B3E | Yes |
It can be deployed on any network that supports the CREATE2
opcode.