Solidity之abi.encode各编码方法使用

什么是智能合约 ABI

ABI = Specification for encoding and decoding

非常精炼的一句话:一套用来编码和解码的规范。 

注意与合约字节码(bytecode)要区分开,字节码只是一串用十六进制数表示的 EVM 操作码。

在 Solidity 文档中描述为: 

Solidity之abi.encode各编码方法使用_第1张图片

 “ABI 是与以太坊生态系统中的合约交互的标准方式。既来自区块链外部,也用于合约之间的交互”。

什么是合约的 JSON ABI

JSON ABI specification for functions
JSON ABI specification for events

合约内部函数和事件的编码规范。 

(1)abi.encodeWithSignature

函数签名:

abi.encodeWithSignature(string memory signature, ...args) returns (bytes memory)

代码示例:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract A {
    function callBTest(
        address _address,
        uint256 _num,
        string memory _message
    ) public returns (bool) {
        (bool success, ) = _address.call(
            abi.encodeWithSignature("test(uint256,string)", _num, _message)
        );
        return success;
    }
}

contract B {
    uint256 public num;
    string public message;

    function test(uint256 _num, string memory _message)
        public
        returns (uint256, string memory)
    {
        num = _num;
        message = _message;
        return (num, message);
    }
}

我们在合约A中通过call的方式,使用内置函数abi.encodeWithSignature对合约B的test函数进行调用。第一个参数为被调用函数的签名(不能包含形参和空格),后面是类似js的剩余参数,给被调用函数传参的(顺序要对应)。

注:test(uint256,string)与test(uint,string)签名哈希是不一样的!

测试:

Solidity之abi.encode各编码方法使用_第2张图片

Solidity之abi.encode各编码方法使用_第3张图片 

(2)abi.encode和abi.encodePacked

bytes4 sig = bytes4(keccak256("test(uint256,string)"));
        bytes memory _bNum = abi.encode(_num);
        bytes memory _bMessage = abi.encode(_message);
        (bool success,) = _address.call(
            abi.encodePacked(sig, _bNum, _bMessage)
        );
        return success;

与上面编码不同的是,这里的函数签名sig是用keccak256算法计算结果取前4个字节得来的,另外其余的参数也都使用abi.encode包装了,最后在统一放入abi.encodePacked函数中(属于非标准编码模式)。

测试过程上同。

(3)abi.encodeWithSelector

 bytes4 sig = bytes4(keccak256("test(uint256,string)"));
        (bool success, ) = _address.call(
            abi.encodeWithSelector(sig, _num, _message)
        );

这种需要函数签名哈希的前4个字节,参数不变,作用相同。

 早在v0.4版本是使用abi.encode(...)函数,不过已废弃了。

测试过程上同。

另外额外一种普通调用其它合约方法的写法:

 B contractB = B(_address);
(uint256 num, string memory message) = contractB.test(_num, _message);
return true;

可能会提示有些变量没有用到,问题不大(或者可以写入event) ,也是能达到同样效果的。

ABI 不仅仅是人类和 EVM之间交互的链接。最重要的是,ABI定义了如何对数据和合约调用进行编码和解码的明确规范。ABI 有助于进一步概念化合约,通过参数列表及其类型可以调用哪些函数以及如何调用。ABI 仅包含有关函数和事件的信息,不包括有关状态变量或修饰符的信息(状态变量定义为public时除外,此时将创建一个全局的getter方法)。

 

参考: Contract ABI Specification — Solidity 0.8.17 documentation

            https://coinsbench.com/solidity-tutorial-all-about-abi-46da8b517e7 

你可能感兴趣的:(智能合约,区块链,abi.encode,solidity)