qidao123.com技术社区-IT企服评测·应用市场

 找回密码
 立即注册

【Solidity】合约交互

[复制链接]
发表于 2025-10-12 18:00:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
Delegate Call

在当前合约通过 delegatecall 可以借用其他合约的方法,以更新当前合约的状态变量:
  1. contract Demo {
  2.     uint public num;
  3.     uint public value;
  4.     address public sender;
  5.     function setVars(uint _num) public payable {
  6.         num += _num;
  7.         value += msg.value;
  8.         sender = msg.sender;
  9.     }
  10. }
  11. contract Proxy {
  12.     uint public num;
  13.     uint public value;
  14.     address public sender;
  15.     function setVars(address _contract, uint _num) public payable {
  16.         (bool success1, ) = _contract.delegatecall(
  17.             abi.encodeWithSignature("setVars(uint256)", _num)
  18.         );
  19.         require(success1, "Error delegatecall");
  20.     }
  21. }
复制代码

  • 摆设 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,这是一种低级调用方式,不会改变区块链状态。
  1. contract TestMultiCall {
  2.     function func1() external view returns (uint, uint) {
  3.         return (1, block.timestamp);
  4.     }
  5.     function func2() external view returns (uint, uint) {
  6.         return (2, block.timestamp);
  7.     }
  8.     // 获取 func1 的函数调用数据
  9.     function getFunc1Data() external pure returns (bytes memory) {
  10.         return abi.encodeWithSelector(this.func1.selector);
  11.     }
  12.     // 获取 func2 的函数调用数据
  13.     function getFunc2Data() external pure returns (bytes memory) {
  14.         return abi.encodeWithSelector(this.func2.selector);
  15.     }
  16. }
  17. contract MultiCall {
  18.     function aggregate(
  19.         address[] calldata targets, // 要调用的目标合约地址
  20.         bytes[] calldata data // 所需的函数调用数据
  21.     ) external view returns (bytes[] memory) {
  22.         require(targets.length == data.length, "MultiCall: invalid input");
  23.         bytes[] memory results = new bytes[](targets.length);
  24.         for (uint i = 0; i < targets.length; i++) {
  25.             (bool success, bytes memory result) = targets[i].staticcall(
  26.                 data[i]
  27.             );
  28.             require(success, "MultiCall: staticcall failed");
  29.             results[i] = result;
  30.         }
  31.         return results;
  32.     }
  33. }
复制代码

  • 摆设 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 允许在单个买卖业务中调用多个合约函数,并在调用过程中共享调用者的上下文。
  1. contract MultiDelegateCall {
  2.     function multiDelegateCall(
  3.         bytes[] calldata data
  4.     ) external payable returns (bytes[] memory results) {
  5.         results = new bytes[](data.length);
  6.         for (uint i = 0; i < data.length; i++) {
  7.             (bool success, bytes memory result) = address(this).delegatecall(
  8.                 data[i]
  9.             );
  10.             require(success, "Delegate call failed");
  11.             results[i] = result;
  12.         }
  13.     }
  14. }
  15. contract TestMultiDelegateCall is MultiDelegateCall {
  16.     event Log(address caller, string funcName, uint value);
  17.     function func1(uint x, uint y) external {
  18.         emit Log(msg.sender, "func1", x + y);
  19.     }
  20.     function func2() external returns (uint) {
  21.         emit Log(msg.sender, "func2", 123);
  22.         return 123;
  23.     }
  24. }
  25. contract Helper {
  26.     function getFunc1Data(uint x, uint y) external pure returns (bytes memory) {
  27.         return abi.encodeWithSelector(TestMultiDelegateCall.func1.selector, x, y);
  28.     }
  29.     function getFunc2Data() external pure returns (bytes memory) {
  30.         return abi.encodeWithSelector(TestMultiDelegateCall.func2.selector);
  31.     }
  32. }
复制代码

  • 摆设 Helper、TestMultiDelegateCall 合约
  • 调用 Helper 的 getFunc1Data、getFunc2Data 方法,获取 func1、func2 函数调用数据 func1Data、func2Data
  • 传入 ["func1Data", "func2Data"],调用 TestMultiDelegateCall 继续的 multiDelegateCall 方法,获取调用结果,应该返回 [bytes 格式的 func1 的返回值, bytes 格式的 func2 的返回值]
  • 观察返回结果,可以看到 bytes 格式的 func1 的返回值 为 0x,这是由于 func1 函数没有返回值
  • 检察 TestMultiDelegateCall 的变乱日记,可以看到 func1、func2 函数的调用者是编辑器所在

在传输以太时必要留意传输的数量,以免出现不合预期的情况:
  1. contract MultiDelegateCall {
  2.     function multiDelegateCall(
  3.         bytes[] calldata data
  4.     ) external payable returns (bytes[] memory results) {
  5.         results = new bytes[](data.length);
  6.         for (uint i = 0; i < data.length; i++) {
  7.             (bool success, bytes memory result) = address(this).delegatecall(
  8.                 data[i]
  9.             );
  10.             require(success, "Delegate call failed");
  11.             results[i] = result;
  12.         }
  13.     }
  14. }
  15. contract TestMultiDelegateCall is MultiDelegateCall {
  16.     mapping(address => uint) public balanceOf;
  17.     function mint() external payable {
  18.         balanceOf[msg.sender] += msg.value;
  19.     }
  20. }
  21. contract Helper {
  22.     function getMintData() external pure returns (bytes memory) {
  23.         return abi.encodeWithSelector(TestMultiDelegateCall.mint.selector);
  24.     }
  25. }
复制代码

  • 摆设 Helper、TestMultiDelegateCall 合约
  • 调用 Helper 的 getMintData 方法,获取 mint 的函数调用数据 mintData
  • 调用 TestMultiDelegateCall 继续的 multiDelegateCall 方法,传入 ["mintData", "mintData", "mintData"],设置以太数为 1 wei
  • 用编辑器所在检察 TestMultiDelegateCall 合约的 balanceOf,可以看到传输的以太数为 3 wei




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

×
登录参与点评抽奖,加入IT实名职场社区
去登录

QQ|手机版|qidao123.com技术社区-IT企服评测▪应用市场 ( 浙ICP备20004199|浙ICP备20004199号 )|网站地图

GMT+8, 2025-12-8 12:59 , Processed in 0.192336 second(s), 30 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表