23-03-04
Last Update:
2023-03-04
call方法以及abi编解码
了解以下编码
更多信息->查看文章
abi.encodeCall
bytes memory data = abi.encodeCall(MyContract.myFunction.selector, [arg1, arg2]);
abi.encodeCall是Solidity中的一个函数,它可以用来对函数调用进行编码。它接受一个函数选择器和一组参数,并返回一个字节数组,该字节数组可以用来调用指定的函数
优点:有类型检查(不是字符串形式)
abi.encodePacked
将给定参数根据其所需最低空间编码。它类似 abi.encode,但是会把其中填充的很多 0 省略。
比如,只用 1 字节来编码 uint 类型。当你想省空间,并且不与合约交互的时候,可以使用 abi.encodePacked,例如算一些数据的 hash(可作数据比较) 时。
abi.encodeWithSignature
与 abi.encode 功能类似,只不过第一个参数为函数签名,比如”foo(uint256,address)”。当调用其他合约的时候可以使用。
函数签名:bytes4(keccak(“函数名(函数类型)”))
abi.endeWithSelector
Selector
相关文章->HERE
selector 可以通过两种方式获取,一种是查询 function.selector
,另一种就是自己计算(如下)
return bytes4(keccak256("函数名(参数类型)")
== return 合约名(address).函数名.selector
与 abi.encodeWithSignature 功能类似,只不过第一个参数为函数选择器,为函数签名 Keccak 哈希的前 4 个字节。
abi.decode
abi.decode 用于解码 abi.encode 生成的二进制编码,将它还原成原本的参数。
(bool b, uint ui, string memory) = abi.decode(data,(bool, uint, string));
写法
address.call{value:xxx, gas:xxx}([bytes])
==address.call.value(xxx).gas(xxx)([bytes])
【右侧用法已被弃用】address.call{value:xxx, gas:xxx}(abi.encodeWithSignature("函数名称(参数类型)"), 参数)
==address.call{value:xxx,gas:xxx}(abi.encodeWithSelector(bytes4(keccak256("参数类型"))),参数)
返回值
(bool success, bytes data)
call函数的返回结果是一个bool与bytes的元组,表示是否成功调用或者失败引起了EVM异常。该方法无法直接访问函数返回结果(因为需要事先知道编码和返回结果大小)
call()
的返回结果即使成功,并不能说操作成功了,只是没有出现异常,有可能调用到了fallback()
函数
调用另一个合约的方法
- 带参情况
(bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}(abi.encodeWithSignature("foo(string,uint256)", "call foo", 123)) );
花括号指定发送以太币数量以及可用gas数量,根据地址_to
对应合约寻找函数foo(string,uint256),后面跟着两个参数
- 无参情况
(bool success, bytes memory data) = _addr.call{value: msg.value}(abi.encodeWithSignature("doesNotExist()"));
1 | //SPDX-License-Identifier: UNLICENSED |
委托调用:Delegatecall
写法
address.delegatecall(abi.encodeCall(A.funA,(arg1, arg2, ...)))
例子
正常的调用其他合约
1 | //SPDX-License-Identifier: MIT |
特别是cl.setXandEther{value:msg.value}(_x);
里面的{value:msg.value}
不要忘记