ABI
(Application Binary Interface,应用二进制接口)是与以太坊智能合约交互的标准.于编码后不包含类型信息,解码时需要注明它们的类型。
ABI编码
有4个函数:
- abi.encode
- abi.encodePacked
- abi.encodeWithSignature
- abi.encodeWithSelector
ABI解码
有1个函数:abi.decode,用于解码abi.encode
的数据
uint x = 10;
address addr = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
string name = "0xAA";
uint[2] array = [5, 6];
ABI
被设计出来跟智能合约交互,他将每个参数填充为32字节的数据,并拼接在一起。如果你要和合约交互,你要用的就是abi.encode
。
function abiEncode() external view returns (bytes memory result) {
result = abi.encode(x, addr, name, array);
// 编码/解码在线地址: https://adibas03.github.io/online-ethereum-abi-encoder-decoder/#/encode
//000000000000000000000000000000000000000000000000000000000000000a 0 ~ 32 (uint = 10)
//0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c71 32~ 64 (address addr = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;)
//00000000000000000000000000000000000000000000000000000000000000a0 64~ 96 (偏移量,指向动态数据的起始位置,a0代表string开始位置 16*10 = 160 ,代表存储位置是160 开始)
//0000000000000000000000000000000000000000000000000000000000000005 96~ 128 (uint[2] array[0] = 5)
//0000000000000000000000000000000000000000000000000000000000000006 128~ 160 (uint[2] array[0] = 5)
//0000000000000000000000000000000000000000000000000000000000000004 160~ 192 (代表string的长度)
//3078414100000000000000000000000000000000000000000000000000000000 192~ 224 (代表 0xAA 的十六进制; 线上转换地址 https://string-functions.com/string-hex.aspx)
}
将给定参数根据其所需最低空间编码。它类似 abi.encode
,但是会把其中填充的很多0
省略。当你想省空间,并且不与合约交互的时候,可以使用abi.encodePacked
,例如算一些数据的hash
时。
function abiEncodePacked() external view returns (bytes memory result) {
result = abi.encodePacked(x, addr, name, array);
// 0x000000000000000000000000000000000000000000000000000000000000000a7a58c0be72be218b41c608b7fe7c5bb630736c713078414100000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006,由于abi.encodePacked对编码进行了压缩,长度比abi.encode短很多。
}
与abi.encode
功能类似,只不过第一个参数为函数签名
。当调用其他合约的时候可以使用
function abiEncodeWithSignature(address _addr, uint256 _x) external returns (uint256) {
(bool success, bytes memory data) = _addr.call(
abi.encodeWithSignature("setX(uint256)", _x)
);
require(success);
uint256 result = abi.decode(data, (uint256));
return result;
}
编码结果与abi.encode
相比前面多了4个字节的函数选择器编码。
与abi.encodeWithSignature
功能类似,只不过第一个参数为函数选择器
,为函数签名
Keccak哈希的前4个字节
function abiEncodeWithSelector(address _addr, uint256 _x)
external
returns (uint256)
{
// bytes4 selector = bytes4(keccak256("setX(uint256)"));
bytes4 selector = B.setX.selector;
(bool success, bytes memory data) = _addr.call(
abi.encodeWithSelector(selector, _x)
);
require(success);
uint256 result = abi.decode(data, (uint256));
return result;
}
与abi.encodeWithSignature
结果一样。