马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
Delegate Call
在当前合约通过 delegatecall 可以借用其他合约的方法,以更新当前合约的状态变量:- contract Demo {
- uint public num;
- uint public value;
- address public sender;
- function setVars(uint _num) public payable {
- num += _num;
- value += msg.value;
- sender = msg.sender;
- }
- }
- contract Proxy {
- uint public num;
- uint public value;
- address public sender;
- function setVars(address _contract, uint _num) public payable {
- (bool success1, ) = _contract.delegatecall(
- abi.encodeWithSignature("setVars(uint256)", _num)
- );
- require(success1, "Error delegatecall");
- }
- }
复制代码
- 摆设 Demo、Proxy 合约
- 传入 Demo 合约的所在、数字(这里为 10),设置以太币数量(这里设置为 100),调用 Proxy 合约的 setVars 方法
- 检察 Proxy 合约,可以看到 num 值加了 10、sender 值为编辑器所在、value 值加了 100
- 检察 Demo 合约,可以看到 num、sender、value 值均未改变
留意:调用合约和实现合约的存储布局必须同等,否则大概会导致数据杂乱。
我们更换 Demo 合约 num 和 value 的位置,再重复上述步调,可以看到 Proxy 合约变成 num 值加了 100、value 值加了 10。这是由于,更换后的 Demo 合约 num 在第 2 个存储槽,value 在第 1 个存储槽,而 Proxy 合约的 num 仍在第 1 个存储槽,value 仍在第 2 个存储槽。
Multi Call
Multi Call 表现在单个买卖业务中调用多个合约函数。
Multi Call 合约通过循环调用多个目标合约的函数,并将结果聚合返回。每个函数调用利用 staticcall,这是一种低级调用方式,不会改变区块链状态。- contract TestMultiCall {
- function func1() external view returns (uint, uint) {
- return (1, block.timestamp);
- }
- function func2() external view returns (uint, uint) {
- return (2, block.timestamp);
- }
- // 获取 func1 的函数调用数据
- function getFunc1Data() external pure returns (bytes memory) {
- return abi.encodeWithSelector(this.func1.selector);
- }
- // 获取 func2 的函数调用数据
- function getFunc2Data() external pure returns (bytes memory) {
- return abi.encodeWithSelector(this.func2.selector);
- }
- }
- contract MultiCall {
- function aggregate(
- address[] calldata targets, // 要调用的目标合约地址
- bytes[] calldata data // 所需的函数调用数据
- ) external view returns (bytes[] memory) {
- require(targets.length == data.length, "MultiCall: invalid input");
- bytes[] memory results = new bytes[](targets.length);
- for (uint i = 0; i < targets.length; i++) {
- (bool success, bytes memory result) = targets[i].staticcall(
- data[i]
- );
- require(success, "MultiCall: staticcall failed");
- results[i] = result;
- }
- return results;
- }
- }
复制代码
- 摆设 TestMultiCall、MultiCall 合约
- 调用 TestMultiCall 的 getFunc1Data、getFunc2Data 方法,获取 func1、func2 的函数调用数据
- 传入 ["TestMultiCall 合约所在", "TestMultiCall 合约所在"] 和 ["getFunc1Data 返回的编码数据", "getFunc2Data 返回的编码数据"],调用 MultiCall 的 aggregate 方法,获取的调用结果应该为 [bytes 格式的 func1 的返回值, bytes 格式的 func2 的返回值]
- 观察返回结果,可以看到 func1、func2 函数返回雷同的时间戳
Multi Delegate Call
Multi Delegate Call 允许在单个买卖业务中调用多个合约函数,并在调用过程中共享调用者的上下文。- contract MultiDelegateCall {
- function multiDelegateCall(
- bytes[] calldata data
- ) external payable returns (bytes[] memory results) {
- results = new bytes[](data.length);
- for (uint i = 0; i < data.length; i++) {
- (bool success, bytes memory result) = address(this).delegatecall(
- data[i]
- );
- require(success, "Delegate call failed");
- results[i] = result;
- }
- }
- }
- contract TestMultiDelegateCall is MultiDelegateCall {
- event Log(address caller, string funcName, uint value);
- function func1(uint x, uint y) external {
- emit Log(msg.sender, "func1", x + y);
- }
- function func2() external returns (uint) {
- emit Log(msg.sender, "func2", 123);
- return 123;
- }
- }
- contract Helper {
- function getFunc1Data(uint x, uint y) external pure returns (bytes memory) {
- return abi.encodeWithSelector(TestMultiDelegateCall.func1.selector, x, y);
- }
- function getFunc2Data() external pure returns (bytes memory) {
- return abi.encodeWithSelector(TestMultiDelegateCall.func2.selector);
- }
- }
复制代码
- 摆设 Helper、TestMultiDelegateCall 合约
- 调用 Helper 的 getFunc1Data、getFunc2Data 方法,获取 func1、func2 函数调用数据 func1Data、func2Data
- 传入 ["func1Data", "func2Data"],调用 TestMultiDelegateCall 继续的 multiDelegateCall 方法,获取调用结果,应该返回 [bytes 格式的 func1 的返回值, bytes 格式的 func2 的返回值]
- 观察返回结果,可以看到 bytes 格式的 func1 的返回值 为 0x,这是由于 func1 函数没有返回值
- 检察 TestMultiDelegateCall 的变乱日记,可以看到 func1、func2 函数的调用者是编辑器所在
在传输以太时必要留意传输的数量,以免出现不合预期的情况:- contract MultiDelegateCall {
- function multiDelegateCall(
- bytes[] calldata data
- ) external payable returns (bytes[] memory results) {
- results = new bytes[](data.length);
- for (uint i = 0; i < data.length; i++) {
- (bool success, bytes memory result) = address(this).delegatecall(
- data[i]
- );
- require(success, "Delegate call failed");
- results[i] = result;
- }
- }
- }
- contract TestMultiDelegateCall is MultiDelegateCall {
- mapping(address => uint) public balanceOf;
- function mint() external payable {
- balanceOf[msg.sender] += msg.value;
- }
- }
- contract Helper {
- function getMintData() external pure returns (bytes memory) {
- return abi.encodeWithSelector(TestMultiDelegateCall.mint.selector);
- }
- }
复制代码
- 摆设 Helper、TestMultiDelegateCall 合约
- 调用 Helper 的 getMintData 方法,获取 mint 的函数调用数据 mintData
- 调用 TestMultiDelegateCall 继续的 multiDelegateCall 方法,传入 ["mintData", "mintData", "mintData"],设置以太数为 1 wei
- 用编辑器所在检察 TestMultiDelegateCall 合约的 balanceOf,可以看到传输的以太数为 3 wei
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|