主页EIPs
EIPsERC-6357
ERC-6357

Single-contract Multi-delegatecall

Allows an EOA to call multiple functions of a smart contract in a single transaction
Last CallStandards Track: ERC
创建时间: 2023-01-18终审截止日期: 2023-11-10
Gavin John (@Pandapip1)
社区讨论原文链接编辑
1 分钟了解

相关视频
欢迎补充好内容
去提交
正文

Abstract

This EIP standardizes an interface containing a single function, multicall, allowing EOAs to call multiple functions of a smart contract in a single transaction, and revert all calls if any call fails.

Motivation

Currently, in order to transfer several ERC-721 NFTs, one needs to submit a number of transactions equal to the number of NFTs being tranferred. This wastes users' funds by requiring them to pay 21000 gas fee for every NFT they transfer.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Contracts implementing this EIP must implement the following interface:

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); }

Rationale

multicallPayable is optional because it isn't always feasible to implement, due to the msg.value splitting.

Backwards Compatibility

This is compatible with most existing multicall functions.

Test Cases

The following JavaScript code, using the Ethers library, should atomically transfer amt units of an ERC-20 token to both addressA and addressB.

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

Reference Implementation

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; } }

Security Considerations

multicallPayable should only be used if the contract is able to support it. A naive attempt at implementing it could allow an attacker to call a payable function multiple times with the same ether.

Copyright and related rights waived via CC0.

扩展阅读
欢迎补充好内容
去提交
相关项目
欢迎补充好内容
去提交

不想错过最新的 EIP 动态?

订阅 EIPs Fun 周刊以跟进相关更新,建⽴你与 EIP 之间的连接 ,更好地建设以太坊。

详情
聚集 EIP 贡献者, 扩展以太坊
资源
GitHub
支持社区