首页 > 其他分享 >Solidity极简入门#27. ABI编码解码

Solidity极简入门#27. ABI编码解码

时间:2023-03-02 20:31:59浏览次数:64  
标签:极简 27 函数 编码 abi memory ABI encode

ABI (Application Binary Interface,应用二进制接口)是与Ethereum智能合约交互的标准。数据基于他们的类型编码;并且由于编码后不包含类型信息,解码时需要注明它们的类型。

Solidity中,ABI编码有4个函数:​​abi.encode​​, ​​abi.encodePacked​​, soli, ​​abi.encodeWithSelector​​。而ABI解码有1个函数:​​abi.decode​​,用于解码abi.encode的数据。这一讲,我们将学习如何使用这些函数。

ABI编码

我们将用编码4个变量,他们的类型分别是uint256, address, string, uint256[2]:

uint x = 10;
address addr = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
string name = "0xAA";
uint[2] array = [5, 6];

abi.encode

将给定参数利用​​ABI规则​​编码。ABI被设计出来跟智能合约交互,他将每个参数填充为32字节的数据,并拼接在一起。如果你要和合约交互,你要用的就是abi.encode。

function encode() public view returns(bytes memory result) {
result = abi.encode(x, addr, name, array);
}

编码的结果为​​0x000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c7100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000043078414100000000000000000000000000000000000000000000000000000000​​,由于​​abi.encode​​将每个数据都填充为32字节,中间有很多0。

abi.encodePacked

将给定参数根据其所需最低空间编码。它类似 abi.encode,但是会把其中填充的很多0省略。比如,只用1字节来编码uint类型。当你想省空间,并且不与合约交互的时候,可以使用abi.encodePacked,例如算一些数据的hash时。

function encodePacked() public view returns(bytes memory result) {
result = abi.encodePacked(x, addr, name, array);
}

编码的结果为​​0x000000000000000000000000000000000000000000000000000000000000000a7a58c0be72be218b41c608b7fe7c5bb630736c713078414100000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006​​,由于​​abi.encodePacked​​对编码进行了压缩,长度比abi.encode短很多。

abi.encodeWithSignature

与​​abi.encode​​功能类似,只不过第一个参数为函数签名,比如"​​foo(uint256,address)​​"。当调用其他合约的时候可以使用。

function encodeWithSignature() public view returns(bytes memory result) {
result = abi.encodeWithSignature("foo(uint256,address,string,uint256[2])", x, addr, name, array);
}

编码的结果为​​0xe87082f1000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c7100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000043078414100000000000000000000000000000000000000000000000000000000​​,等同于在​​abi.encode​​编码结果前加上了4字节的函数选择器说明。 说明: 函数选择器就是通过函数名和参数进行签名处理(Keccak–Sha3)来标识函数,可以用于不同合约之间的函数调用

abi.encodeWithSelector

与​​abi.encodeWithSignature​​功能类似,只不过第一个参数为函数选择器,为函数签名Keccak哈希的前4个字节。

function encodeWithSelector() public view returns(bytes memory result) {
result = abi.encodeWithSelector(bytes4(keccak256("foo(uint256,address,string,uint256[2])")), x, addr, name, array);
}

编码的结果为​​0xe87082f1000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000007a58c0be72be218b41c608b7fe7c5bb630736c7100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000043078414100000000000000000000000000000000000000000000000000000000​​,与​​abi.encodeWithSignature​​结果一样。

ABI解码

abi.decode

abi.decode用于解码abi.encode生成的二进制编码,将它还原成原本的参数。

function decode(bytes memory data) public pure returns(uint dx, address daddr, string memory dname, uint[2] memory darray) {
(dx, daddr, dname, darray) = abi.decode(data, (uint, address, string, uint[2]));
}

我们将​​abi.encode​​的二进制编码输入给decode,将解码出原来的参数:

Solidity极简入门#27. ABI编码解码_solidity

在remix上验证

  • 部署合约查看​​abi.encode​​方法的编码结果

Solidity极简入门#27. ABI编码解码_solidity_02

  • 对比验证四种编码方法的异同点

Solidity极简入门#27. ABI编码解码_智能合约_03

  • 查看​​abi.decode​​方法的解码结果

Solidity极简入门#27. ABI编码解码_solidity_04

ABI的使用场景

  1. 在合约开发中,ABI常配合call来实现对合约的底层调用。
bytes4 selector = contract.getValue.selector;

bytes memory data = abi.encodeWithSelector(selector, _x);
(bool success, bytes memory returnedData) = address(contract).staticcall(data);
require(success);

return abi.decode(returnedData, (uint256));
  1. ethers.js中常用ABI实现合约的导入和函数调用。
const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer);
/*
* Call the getAllWaves method from your Smart Contract
*/
const waves = await wavePortalContract.getAllWaves();
  1. 对不开源合约进行反编译后,某些函数无法查到函数签名,可通过ABI进行调用。
  • 0x533ba33a() 是一个反编译后显示的函数,只有函数编码后的结果,并且无法查到函数签名

Solidity极简入门#27. ABI编码解码_区块链_05

Solidity极简入门#27. ABI编码解码_ethereum_06

  • 这种情况无法通过构造interface接口或contract来进行调用

Solidity极简入门#27. ABI编码解码_智能合约_07

这种情况下,就可以通过ABI函数选择器来调用

bytes memory data = abi.encodeWithSelector(bytes4(0x533ba33a));

(bool success, bytes memory returnedData) = address(contract).staticcall(data);
require(success);

return abi.decode(returnedData, (uint256));

总结

在Ethereum中,数据必须编码成字节码才能和智能合约交互。这一讲,我们介绍了4种abi编码方法和1种abi解码方法。

标签:极简,27,函数,编码,abi,memory,ABI,encode
From: https://blog.51cto.com/sleep666/6096766

相关文章

  • luogu P6276 [USACO20OPEN]Exercise P
    题面传送门首先考虑一个固定排列的答案是什么。考虑它的若干置换环,应该是所有环环长的LCM,所有数都会转回本来的位置。现在变成计算所有环的环长的LCM的积的问题。注意......
  • Linux极简入门系列(六):其它补充
    Linux极简入门系统目录:1、系统安装和配置(VMware/CentOS、WSL/ubuntu)2、Linux的目录结构和常用操作3、vim文本编辑器4、用户和文件权限5、软件和服务管理6、其它补......
  • 代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素。
    LeetCode704-二分查找题目描述:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返......
  • LOJ 3276 JOISC 2020 Day2 遗迹 题解 (计数DP)
    LOJ链接UOJ链接观察一下n次地震的过程,发现最后会有n个石柱高度为0,\(1,2\cdotsn\)高度的石柱各有一个。假设现在已经确定了一种初始高度状态,我们来看看最后哪些石柱高度......
  • 2023/2/27每日总结
    以下为今日课上所写代码packageText;importjava.io.*;importjava.util.ArrayList;importjava.util.List;importjava.util.Scanner;/*关于文件导入并找出最长的接龙单......
  • ABC-278解题报告
    比赛传送门D.AllAssignPointAdd题意:给你一个数组\(a\),需要支持:全局赋值、单点加、单点查询。做法一维护最近一次全局赋值操作及每个位置在该操作后的增加量,当进......
  • ABC-277解题报告
    比赛传送门B.PlayingCardsValidation题意:有\(n\)个长度为\(2\)的字符串,判断是否满足以下条件:第一个字符为HDCS之一。第二个字符为A23456789TJQK之一。字......
  • ABC-279解题报告
    比赛传送门C.RANDOM题意:给你两个01矩阵\(S,T\),问是否可以将\(S\)以列为单位重新排列得到\(T\)。判断\(S,T\)的每列是否可以一一对应即可做法一以列为单位......
  • ABC-271解题报告
    C.Manga题意:有一本书有\(n\)卷,你需要从第一卷开始依次看,一旦没有某一卷就停止。在看之前你可以进行若干次操作,每次卖掉任意两卷并买新的任意一卷。问操作结束后最多能......
  • ABC275D-Yet-Another-Recursive-Function题解
    题目传送门题意:定义一个\(\mathbb{N}\to\mathbb{N}\)的函数\(f(x)=\begin{cases}1&x=0\\f(\lfloor\frac{x}{2}\rfloor)+f(\lfloor\frac{x}{3}\rfloor)&\text{otherwis......