Ale*_*hin 6 solidity rsk ethers.js hardhat
我有 2 个交互的智能合约,正在Hardhat中开发/测试并部署到RSK。其中之一是具有功能的ERC1363 支付代币transferAndCall(address,uint256,bytes),第二个是代币接收器,buy(address,uint,uint,bytes3)我需要对其函数调用进行链下编码并发送到代币的transferAndCall函数bytes参数。ERC1363 合约将代币从发送者的账户转移到接收者智能合约的账户,然后在同一交易中调用接收者的onTransferReceived(address,address,uint256,bytes),其中最后一个bytes参数应该是编码buy函数调用。
这是我的接收者智能合约:
contract TokenReceiver is IERC1363Receiver {
IERC1363 acceptedToken;
constructor(IERC1363 _acceptedToken) {
acceptedToken = _acceptedToken;
}
event PurchaseMade(address indexed sender, uint tokensPaid, uint productAmount, bytes3 color);
function buy(address sender, uint tokensPaid, uint productAmount, bytes3 color) public {
// allowed to be called only via the accepted token
require(msg.sender == address(acceptedToken), "I accept purchases in Payable Tokens");
emit PurchaseMade(sender, tokensPaid, productAmount, color);
}
function onTransferReceived(address operator, address sender, uint256 tokensPaid, bytes calldata data) external override (IERC1363Receiver) returns (bytes4) {
// TODO: decode calldata and call `buy` function
return this.onTransferReceived.selector;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我通过将函数的签名和参数编码buy在一起来组装调用数据的方法:
contract TokenReceiver is IERC1363Receiver {
IERC1363 acceptedToken;
constructor(IERC1363 _acceptedToken) {
acceptedToken = _acceptedToken;
}
event PurchaseMade(address indexed sender, uint tokensPaid, uint productAmount, bytes3 color);
function buy(address sender, uint tokensPaid, uint productAmount, bytes3 color) public {
// allowed to be called only via the accepted token
require(msg.sender == address(acceptedToken), "I accept purchases in Payable Tokens");
emit PurchaseMade(sender, tokensPaid, productAmount, color);
}
function onTransferReceived(address operator, address sender, uint256 tokensPaid, bytes calldata data) external override (IERC1363Receiver) returns (bytes4) {
// TODO: decode calldata and call `buy` function
return this.onTransferReceived.selector;
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
onTransferReceived函数内的呼叫数据?小智 6
您可以利用内联汇编来解码字节数据。创建一个pure包含以下内容的辅助函数:\n\xe2\x80\x8b
function decode(bytes memory data) private pure returns(bytes4 selector, uint productAmount, bytes3 color) {\n assembly {\n // load 32 bytes into `selector` from `data` skipping the first 32 bytes\n selector := mload(add(data, 32))\n productAmount := mload(add(data, 64))\n color := mload(add(data, 96))\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b\n此处mload(0xAB)加载位于内存地址 0xAB 处的一个字(32 字节),并对add(0xAB, 0xCD)两个值求和\n\xe2\x80\x8b\n有关 Solidity 中内联汇编的更多信息,请参阅本文。\n\xe2 \x80\x8b\n接下来,您可以在合约中使用创建的函数:\n\xe2\x80\x8b
(bytes4 selector, uint productAmount, bytes3 color) =\n decode(data);\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b\n既然有了选择器和其他参数,就可以构造函数调用数据\n\xe2\x80\x8b
\nbytes memory funcData =\n abi.encodeWithSelector(selector, sender, tokensPaid, productAmount, color);\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b\n现在您可以进行低级调用来调用相应的函数\n\xe2\x80\x8b
\n(bool success,) = address(this).call(funcData);\nrequire(success, "call failed");\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b\n警告:\n请记住,使用上述方法\n允许攻击者能够调用合约中的任何函数。\n请小心使用低级别调用。\n\xe2\x80\x8b \n为避免这种情况,请在调用之前验证函数选择器,\n如下所示:\n\xe2\x80\x8b
\nif (selector == this.buy.selector) {\n buy(sender, tokensPaid, productAmount, color);\n}\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b\n因此,你的onTransferReceived函数可能看起来像这样:\n\xe2\x80\x8b
function onTransferReceived(address operator, address sender, uint256 tokensPaid, bytes calldata data) external override (IERC1363Receiver) returns (bytes4) {\n require(msg.sender == address(acceptedToken), "I accept purchases in Payable Tokens");\n\xe2\x80\x8b\n (bytes4 selector, uint productAmount, bytes3 color) =\n decode(data);\n\xe2\x80\x8b\n if (selector == this.buy.selector) {\n buy(sender, tokensPaid, productAmount, color);\n }\n\xe2\x80\x8b\n return this.onTransferReceived.selector;\n }\nRun Code Online (Sandbox Code Playgroud)\n
//Define struct within the contract, but outside the function
struct BuyParams {
bytes4 buySigHash;
uint256 productAmount;
bytes3 color;
}
// within onTransferReceived: decode the calldata:
BuyParams memory decoded = abi.decode(
data,
(BuyParams)
);
//Now use as function arguments by passing:
decoded.buySigHash,
decoded.productAmount,
decoded.color,
Run Code Online (Sandbox Code Playgroud)
添加:您也许可以通过更改调用数据的顺序来节省gas:
from:
bytes4 buySigHash;
uint256 productAmount;
bytes3 color;
to:
uint256 productAmount;
bytes4 buySigHash;
bytes3 color;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4564 次 |
| 最近记录: |