3

单个合约中多个交易的模式

 11 months ago
source link: https://willzhuang.github.io/2023/04/20/%E5%8D%95%E4%B8%AA%E5%90%88%E7%BA%A6%E4%B8%AD%E5%A4%9A%E4%B8%AA%E4%BA%A4%E6%98%93%E7%9A%84%E6%A8%A1%E5%BC%8F/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

单个合约中多个交易的模式

2023-04-20

早期空头 NFT/ERC20 Token 的话,更多需要用户来做 withdraw。本文章的设计模式是由发行方来发送 NFT/ERC20 Token 给到用户。同样适用于多个资产同时转账的场景。

合约接口:

pragma solidity ^0.8.0;

interface IMulticall {
/// @notice Takes an array of abi-encoded call data, delegatecalls itself with each calldata, and returns the abi-encoded result
/// @dev Reverts if any delegatecall reverts
/// @param data The abi-encoded data
/// @returns results The abi-encoded return values
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results);

/// @notice OPTIONAL. Takes an array of abi-encoded call data, delegatecalls itself with each calldata, and returns the abi-encoded result
/// @dev Reverts if any delegatecall reverts
/// @param data The abi-encoded data
/// @param values The effective msg.values. These must add up to at most msg.value
/// @returns results The abi-encoded return values
function multicallPayable(bytes[] calldata data, uint256[] values) external payable virtual returns (bytes[] memory results);
}

multicallPayable 是可选的,因为由于 msg.value,它并不总是可行的。

以下是最为简陋的实现方式。

pragma solidity ^0.8.0;

/// Derived from OpenZeppelin's implementation
abstract contract Multicall is IMulticall {
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
(bool success, bytes memory returndata) = address(this).delegatecall(data);
require(success);
results[i] = returndata;
}
return results;
}
}

multicallPayable 只应在合约能够支持时使用。以上实现可能允许攻击者使用相同的以太币多次调用支付函数。

调用方法/测试方法

以下 JavaScript 代码使用 Ethers 库,应自动将 ERC-20 Token 的 amt 单位传输到地址 A 和地址 B。

await token.multicall(await Promise.all([
token.interface.encodeFunctionData('transfer', [ addressA, amt ]),
token.interface.encodeFunctionData('transfer', [ addressB, amt ]),
]));

https://github.com/willzhuang/multicall

https://github.com/ethereum/EIPs/blob/master/EIPS/eip-6357.md


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK