赞
踩
合约如下:
-
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.7;
-
- struct User{
- uint8 userType;
- uint8 age;
- }
-
- contract Test {
- User[] public users;
- mapping(address => User) public user;
-
- function testCall(bytes memory _payload) external {
- (bool success, ) = address(this).call(_payload);
- require(success, "call fail.");
- }
-
- function testCalled(address[] memory _addr, User[] memory _user) external {
- require(_addr.length == _user.length, "Len is not the same.");
- for (uint8 i = 0; i < _user.length; i++) {
- user[_addr[i]] = _user[i];
- users.push(_user[i]);
- }
- }
-
- function getCallBytes() external pure returns (bytes memory){
- address[] memory _addrs = new address[](1);
- _addrs[0] = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
-
- User memory _user = User(1,25);
- User[] memory _users = new User[](1);
- _users[0] = _user;
-
- bytes memory payload = abi.encodeWithSignature("testCalled(address[],(uint8,uint8)[])", _addrs, _users);
- return payload;
- }
-
- }
在Remix中进行测试,通过测试函数 getCallBytes 生成payload,此函数中参数值是固定的
在etherjs 测试合约时,需要生成上面合约函数getCallBytes生成的payload,参数值都相同,写法如下:
- const { expect } = require('chai');
- const { ethers } = require('hardhat');
-
- describe("测试合约", function () {
- let testContract;
- let owner;
-
- beforeEach(async () => {
- [owner] = await ethers.getSigners();
- console.log("owner地址: ", owner.address);
-
- console.log("================ 部署合约 ==================");
- const TestContract = await ethers.getContractFactory("Test");
-
- testContract = await TestContract.deploy();
-
- //验证合约地址
- expect(testContract).to.not.equal(ethers.constants.AddressZero);
- console.log("合约地址: ", testContract.address);
- });
-
-
- it("1、测试指令集", async function () {
-
- console.log("================ 生成指令集 ==================");
- //指令集 - 函数参数 - 账户地址
- const newAddrs = [owner.address];
- //指令集 - 函数参数 - 用户信息
- const newUsers = [
- {
- userType: 1,
- age: 25
- }
- ]
-
- //指令集 - Solidity中函数的名称和参数类型
- const functionName = "testCalled";
- const functionParamType = ["address[]", "(uint8,uint8)[]"];
-
- //指令集 - 用于编码函数名称和参数类型的selector
- const selector = ethers.utils.hexDataSlice(ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`${functionName}(${functionParamType.join(',')})`)), 0, 4);
-
- //指令集 - 用于编码函数参数的ABI编码器
- const encodedData = ethers.utils.defaultAbiCoder.encode(
- ["address[]", "(uint8 userType, uint8 age)[]"],
- [newAddrs, newUsers]
- );
-
- //指令集 - 构造包含函数选择器的payload
- const payload = selector + encodedData.substr(2); // 去除前面的'0x'
-
- console.log("payload:", payload);
-
- console.log("================ 调用合约方法 ==================");
- //调用合约方法
- await testContract.testCall(payload);
-
- console.log("================ 验证执行方法结果 ==================");
- //验证用户是否已加
-
- const user = await testContract.user(owner.address);
- expect(user.userType).to.be.equal(newUsers[0].userType);
- expect(user.age).to.be.equal(newUsers[0].age);
- console.log("用户信息", user);
- });
-
- });
测试结果如下,打印出payload, 与合约函数getCallBytes生成的payload是一致的。
注:使用call调用的函数需要是external,即上面的testCalled函数是external
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。