什么是智能合约 ABI

ABI = Specification for encoding and decoding

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

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

在 Solidity 文档中描述为:

“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.0pragma 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)publicreturns (uint256, string memory){num = _num;message = _message;return (num, message);}}

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

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

测试:

(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