当前位置:   article > 正文

Ethersjs生成指令集,为Solidity合约中call参数使用_ethers.utils.defaultabicoder.encode 结构体

ethers.utils.defaultabicoder.encode 结构体

合约如下:

  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.7;
  3. struct User{
  4. uint8 userType;
  5. uint8 age;
  6. }
  7. contract Test {
  8. User[] public users;
  9. mapping(address => User) public user;
  10. function testCall(bytes memory _payload) external {
  11. (bool success, ) = address(this).call(_payload);
  12. require(success, "call fail.");
  13. }
  14. function testCalled(address[] memory _addr, User[] memory _user) external {
  15. require(_addr.length == _user.length, "Len is not the same.");
  16. for (uint8 i = 0; i < _user.length; i++) {
  17. user[_addr[i]] = _user[i];
  18. users.push(_user[i]);
  19. }
  20. }
  21. function getCallBytes() external pure returns (bytes memory){
  22. address[] memory _addrs = new address[](1);
  23. _addrs[0] = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
  24. User memory _user = User(1,25);
  25. User[] memory _users = new User[](1);
  26. _users[0] = _user;
  27. bytes memory payload = abi.encodeWithSignature("testCalled(address[],(uint8,uint8)[])", _addrs, _users);
  28. return payload;
  29. }
  30. }

Remix中进行测试,通过测试函数 getCallBytes 生成payload,此函数中参数值是固定的

在etherjs 测试合约时,需要生成上面合约函数getCallBytes生成的payload,参数值都相同,写法如下:

  1. const { expect } = require('chai');
  2. const { ethers } = require('hardhat');
  3. describe("测试合约", function () {
  4. let testContract;
  5. let owner;
  6. beforeEach(async () => {
  7. [owner] = await ethers.getSigners();
  8. console.log("owner地址: ", owner.address);
  9. console.log("================ 部署合约 ==================");
  10. const TestContract = await ethers.getContractFactory("Test");
  11. testContract = await TestContract.deploy();
  12. //验证合约地址
  13. expect(testContract).to.not.equal(ethers.constants.AddressZero);
  14. console.log("合约地址: ", testContract.address);
  15. });
  16. it("1、测试指令集", async function () {
  17. console.log("================ 生成指令集 ==================");
  18. //指令集 - 函数参数 - 账户地址
  19. const newAddrs = [owner.address];
  20. //指令集 - 函数参数 - 用户信息
  21. const newUsers = [
  22. {
  23. userType: 1,
  24. age: 25
  25. }
  26. ]
  27. //指令集 - Solidity中函数的名称和参数类型
  28. const functionName = "testCalled";
  29. const functionParamType = ["address[]", "(uint8,uint8)[]"];
  30. //指令集 - 用于编码函数名称和参数类型的selector
  31. const selector = ethers.utils.hexDataSlice(ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`${functionName}(${functionParamType.join(',')})`)), 0, 4);
  32. //指令集 - 用于编码函数参数的ABI编码器
  33. const encodedData = ethers.utils.defaultAbiCoder.encode(
  34. ["address[]", "(uint8 userType, uint8 age)[]"],
  35. [newAddrs, newUsers]
  36. );
  37. //指令集 - 构造包含函数选择器的payload
  38. const payload = selector + encodedData.substr(2); // 去除前面的'0x'
  39. console.log("payload:", payload);
  40. console.log("================ 调用合约方法 ==================");
  41. //调用合约方法
  42. await testContract.testCall(payload);
  43. console.log("================ 验证执行方法结果 ==================");
  44. //验证用户是否已加
  45. const user = await testContract.user(owner.address);
  46. expect(user.userType).to.be.equal(newUsers[0].userType);
  47. expect(user.age).to.be.equal(newUsers[0].age);
  48. console.log("用户信息", user);
  49. });
  50. });

测试结果如下,打印出payload, 与合约函数getCallBytes生成的payload是一致的。

注:使用call调用的函数需要是external,即上面的testCalled函数是external

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/877797
推荐阅读
相关标签
  

闽ICP备14008679号