假设我希望我的合同(在装配中)更高效,并且能够自己处理一个比标准msg.data更高效的反序列化。
我愿意把时间花在客户身上,这样合同处理才能更高效--基本的问题是,我在客户端应该做些什么来调用完全定制的msg.data,包括函数选择器?
foo(bytes memory encodedParams)
有什么方法可以让我接管整个msg.data,包括函数选择器吗?我该怎么从客户那里打那个电话?
发布于 2022-02-22 09:56:46
问题是你想要怎样的习惯。一般来说,我会从合同方面开始。
使用Solidity函数选择器并不是真正的要求。这主要是一个允许在不同的库和契约中容易重用的标准。
您可以使用回退方法使自定义方法具有稳健性:
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
contract Bytecode {
fallback(bytes calldata data) external returns (bytes memory) {
if (bytes4(data) == 0x0000dead) {
return "Dead";
}
return "Alive";
}
}这可以通过阵列切片扩展到使用自定义参数编码。让我们假设我们希望使用打包编码来优化calldata大小:
contract Custom {
fallback(bytes calldata data) external returns (bytes memory) {
if (bytes4(data) == 0x0000dead) {
uint8 hasAddress = uint8(bytes1(data[4:5]));
address someAddress = address(bytes20(data[5:25]));
if (hasAddress > 0) {
return abi.encode(someAddress);
}
return "Dead";
}
return "Alive";
}
}现在,这个契约可以使用可靠的打包编码来调用。
例如,如何在坚实的环境中调用它:
(bool success, bytes memory data) = custom.call(abi.encodePacked(bytes4(0x0000dead), true, this));例如,如何通过醚提供者调用它:
const data = await provider.call({
to: "<your_contract_address>",
data: ethers.utils.solidityPack(["bytes4", "boolean", "address"], ["0x0000dead", true, "0xE5f2A565Ee0Aa9836B4c80a07C8b32aAd7978e22"])
})这些调用返回原始数据,要处理响应,仍然需要对其进行解码。
例如如何在坚实的情况下解码它:
(address response) = abi.decode(data, (address));例如,如何通过醚类AbiCoder调用它:
const [response] = ethers.utils.defaultAbiCoder.decode([ "address" ], data);用这种方法你可以做各种各样的魔术。但这是非常低的水平,在许多情况下,只会降低您的呼叫数据气体成本。许多气体成本不是由calldata编码造成的,而是由对calldata和一般变量的可靠性强制执行的检查造成的。
其中一些支票是:
arrays和bytes )的边界检查address或boolean这些检查提高了合同的安全性,并防止意外流被利用。
其中一些检查可以使用unchecked区块禁用。但是,如果您想要完全优化它,就必须使用YUL/装配。
对于使用YUL进行自定义参数编码的示例,您可以查看来自安全团队的多发送合同。在这里,它还使用打包编码,您可以看到示例代码如何对多发送实用模块中的以太类数据执行编码。
发布于 2022-02-22 08:28:19
首先,需要计算ABI编码的函数调用数据字符串,如下所示:
const data = web3.eth.abi.encodeFunctionCall({
name: 'insertYourFunctionName',
type: 'function',
inputs: [{
type: 'insertSolidityTypeOfParam1',
name: 'insertNameOfParam1'
},{
type: 'insertSolidityTypeOfParam2',
name: 'insertNameOfParam2'
},
...
]}, [insertValueOfParam1, insertValueOfParam2, ...]);在您的具体情况下,计算的数据如下:
const data = web3.eth.abi.encodeFunctionCall({
name: 'foo',
type: 'function',
inputs: [{
type: 'bytes',
name: 'encodedParams'
}]}, [insertEncodedParamsString]);虽然您不需要导入ABI文件,但是您确实需要了解要调用的函数的结构。
下一步是用计算的数据发送实际事务,如下所示:
await web3.eth.sendTransaction({
from: yourWalletAddress,
to: contractAddress,
data: data
});因此,实际上,当您使用ABI进行标准的web3函数调用时,上面的内容将与在引擎盖下发生的情况相同:
const contract = new Contract(abi, contractAddress);
await contract.methods.insertYourFunctionName(
insertValueOfParam1,
insertValueOfParam2,
...
).send({ from: yourWalletAddress });或者在你的情况下,会是:
const contract = new Contract(abi, contractAddress);
await contract.methods.foo(
insertEncodedParamsString
).send({ from: yourWalletAddress });https://ethereum.stackexchange.com/questions/114146
复制相似问题