Skip to content

Latest commit

 

History

History
97 lines (69 loc) · 3.82 KB

File metadata and controls

97 lines (69 loc) · 3.82 KB

ABI编码解码

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.encode

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.encodePacked

将给定参数根据其所需最低空间编码。它类似 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.encodeWithSignature

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.encodeWithSelector

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结果一样。