以太坊的 Multicall 是一种通过一次区块链请求来批量查询多个智能合约数据的技术。这种方法可以有效减少链上的读取操作,提高效率,并节省 gas 费用。以下是 Multicall 实现的基本原理和步骤:
1. 概念
Multicall 允许用户将多个合约调用组合成一个单一的合约调用。这样,用户只需要进行一次交易,就可以获得多个数据点的结果。这种技术特别适用于需要从多个合约中查询数据的情况,比如去中心化金融(DeFi)应用中。
2. 实现步骤
- 定义一个 Multicall 合约:
Multicall 合约的核心是一个能够接收多个调用数据并返回相应结果的智能合约。这个合约通常具有一个aggregate
方法,该方法可以接受多个调用数据,并返回这些调用的数据结果。 - 调用数据的格式:
每个调用数据通常包括合约地址、调用的函数签名以及参数。Multicall 合约将这些调用数据打包并进行处理。 - 执行多重调用:
Multicall 合约内部的aggregate
方法会使用低级call
或staticcall
操作来执行每个调用,并收集它们的返回值。每个调用的结果都会被编码到一个结果数组中。 - 返回结果:
Multicall 合约将每个调用的结果打包到一个结构中,并将其返回给调用者。调用者可以从返回的结果中提取所需的数据。
3. 示例代码
// Multicall
/**
*Submitted for verification at Etherscan.io on 2019-06-10
*/
pragma solidity >=0.5.0;
pragma experimental ABIEncoderV2;
/// @title Multicall - Aggregate results from multiple read-only function calls
/// @author Michael Elliot <mike@makerdao.com>
/// @author Joshua Levine <joshua@makerdao.com>
/// @author Nick Johnson <arachnid@notdot.net>
contract Multicall {
struct Call {
address target;
bytes callData;
}
function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) {
blockNumber = block.number;
returnData = new bytes[](calls.length);
for(uint256 i = 0; i < calls.length; i++) {
(bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
require(success);
returnData[i] = ret;
}
}
}
// Multicall3
/**
*Submitted for verification at Etherscan.io on 2022-03-09
*/
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;
/// @title Multicall3
/// @notice Aggregate results from multiple function calls
/// @dev Multicall & Multicall2 backwards-compatible
/// @dev Aggregate methods are marked `payable` to save 24 gas per call
/// @author Michael Elliot <mike@makerdao.com>
/// @author Joshua Levine <joshua@makerdao.com>
/// @author Nick Johnson <arachnid@notdot.net>
/// @author Andreas Bigger <andreas@nascent.xyz>
/// @author Matt Solomon <matt@mattsolomon.dev>
contract Multicall3 {
struct Call {
address target;
bytes callData;
}
/// @notice Backwards-compatible call aggregation with Multicall
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return returnData An array of bytes containing the responses
function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) {
blockNumber = block.number;
uint256 length = calls.length;
returnData = new bytes[](length);
Call calldata call;
for (uint256 i = 0; i < length;) {
bool success;
call = calls[i];
(success, returnData[i]) = call.target.call(call.callData);
require(success, "Multicall3: call failed");
unchecked { ++i; }
}
}
}
在这个示例中,aggregate
方法接收一个字节数组,其中每个字节数组表示一个合约调用。staticcall
被用于执行这些调用,并收集结果。
4. 使用 Multicall
开发者可以使用现有的 Multicall 实现(比如 Multicall v1 和 Multicall v2)来减少与以太坊区块链的交互次数。Multicall 可以用于各种前端界面、后端服务和去中心化应用(DApps)中,以提高数据获取效率。
5. 优化与扩展
Multicall 的实现可以根据具体需求进行优化。例如,可以考虑缓存机制、优化数据打包和解码过程,或者增加对复杂查询的支持。
总结
Multicall 是一种通过批量查询减少区块链操作次数的有效技术,它通过将多个调用打包成一个请求来提高效率,减少 gas 费用。在以太坊生态系统中,Multicall 已被广泛应用于数据聚合和去中心化金融服务中。
个人总结
- Multicall 有 n 多个版本,还在持续迭代中,核心功能基本没有变过,目前使用的是 Multicall3
- Multicall ETH 主网 URLhttps://etherscan.io/address/0xeefba1e63905ef1d7acba5a8513c70307c1ce441#code
- Multicall3 ETH 主网 URLhttps://etherscan.io/address/0xcA11bde05977b3631167028862bE2a173976CA11#code
参考链接
查看各个链上 Multicall3 部署的合约地址:https://www.multicall3.com/deployments
https://github.com/makerdao/multicall
https://www.multicall3.com/
https://learnblockchain.cn/question/3794
https://learnblockchain.cn/article/3573
评论前必须登录!
注册