什么是智能合约 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.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)签名哈希是不一样的!
测试:
(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