-
Notifications
You must be signed in to change notification settings - Fork 982
Add ERC: Crosschain Token Interface #692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 17 commits
40b7b01
88e4244
f5c5140
7a22c41
f68b199
c70b2aa
2aadee3
95f4221
0eb7d1f
2edb932
a587407
0530449
9ffe3bc
59e733a
1946670
6e815b8
dae604d
b7022c7
5854570
bcea9fe
4fc3c98
1c283af
5d26ebb
34983ad
c1fae24
bf1ebe7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| --- | ||
| eip: 7802 | ||
| title: Crosschain Token Interface | ||
| description: Minimal token interface for cross-chain transfers | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Too many standards claim to be minimal. I'd recommend removing this, and using your description to further elaborate on the ideas introduced in your title.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Modified this section, let me know your thoughts now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can someone here explain how to view/claim tokens or prizes that were claimed too late because I didn't understand? I hope for the information |
||
| author: skeletor (@skeletor-spaceman), parti (@0xParticle), joxes (@Joxess), ng (@0xng), agus duha (@agusduha), disco (@0xDiscotech), gotzen <gotzen@defi.sucks>, 0age <0age@uniswap.org>, Mark Tyneway <mark@oplabs.co>, Zain Bacchus <zain@oplabs.co>, Matt Solomon <msolomon@oplabs.co>, Maurelian <maurelian@protonmail.ch>, Blaine Malone (@blmalone) | ||
| discussions-to: https://ethereum-magicians.org/t/erc-7802-crosschain-token-interface/21508 | ||
| status: Draft | ||
| type: Standards Track | ||
| category: ERC | ||
| created: 2024-10-30 | ||
| requires: 165 | ||
|
0xParti marked this conversation as resolved.
Outdated
|
||
| --- | ||
|
|
||
| ## Abstract | ||
|
|
||
| This standard introduces a minimal interface for tokens to communicate cross-chain. It allows bridges with mint and burn rights to send and relay token transfers with a standardized API. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not bad, but I'd like to see a bit more technical meat here. Could you sketch out how your proposal operates, in addition to the description you already have.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added more technical details. |
||
|
|
||
| ## Motivation | ||
|
|
||
| All rollups and multiple important sidechains (Gnosis and Polygon PoS, among others) implement canonical bridges that embed their security into some part of the network's core architecture. These bridges do not have mint/burn rights over original tokens, so they usually lock (unlock) liquidity on the native chain and then mint (burn) a non-equivalent representation on the other. Mint/burn is used because the native token is non-existent on that side, so they must create a new representation. | ||
|
|
||
| However, each bridge implements a different interface for minting/burning on non-native chains. For example, L1 bridged tokens need to support the `OptimismMintableERC20` specification when bridged (minted) to the OP Stack, but the `IArbToken` interface when bridged to the Arbitrum Stack. | ||
|
|
||
| This interface fragmentation is a massive issue in cross-chain communication among chains via third-party bridges or future canonical solutions. At this point, it is clear that every bridge would benefit from a standardized interface for minted/burnt tokens. | ||
|
|
||
| There have been different attempts in the past to standardize token-bridging interfaces. However, third-party providers are also developing cross-chain token frameworks, such as NTT by Wormhole and OFT by LayerZero. Each framework defines its features, like rate limits and fee switches, and implements its mint and burn versions. The resultant interfaces become highly specific, lacking naming conventions and structures. | ||
|
0xParti marked this conversation as resolved.
Outdated
|
||
|
|
||
| The proposed interface includes the most relevant and minimal set of actions used by most of these standards. These actions also do not require any governance or owner participation, in contrast, for instance, to set rate limits. | ||
|
|
||
| ## Specification | ||
|
|
||
| This ERC introduces the `IERC7802` interface. | ||
|
|
||
| ### Interface Identification | ||
|
|
||
| The interface identifier for `IERC7802` is **`0x33331994`**, calculated according to [ERC-165](./eip-165.md) as the XOR of the function selectors of the two functions in the interface: | ||
|
|
||
| ```solidity | ||
| bytes4 constant INTERFACE_ID_IERC7802 = | ||
| bytes4(keccak256("crosschainMint(address,uint256)")) ^ | ||
| bytes4(keccak256("crosschainBurn(address,uint256)")); | ||
| ``` | ||
|
|
||
| or via Solidity as | ||
|
|
||
| ```solidity | ||
| type(IERC7802).interfaceId | ||
| ``` | ||
|
|
||
| Implementors MUST ensure that the `supportsInterface` method of ERC-165 returns true for this interface ID to indicate support for `IERC7802`. | ||
|
|
||
|
|
||
| ### Methods | ||
|
|
||
| **`crosschainMint`** | ||
|
|
||
| Mints `_amount` of token to address `_account`. | ||
|
|
||
| This function works as the minting entry point for bridge contracts. Each implementation is responsible for its access control logic. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can move the access control notes on each method to the security considerations section.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Security considerations mention this issue explicitly. I will remove these considerations from the method description to minimize redundancy. |
||
|
|
||
| ```solidity | ||
| function crosschainMint(address _account, uint256 _amount) external; | ||
| ``` | ||
|
|
||
| **`crosschainBurn`** | ||
|
|
||
| Burns `_amount` of token from address `_account`. | ||
|
|
||
| This function works as the burning entry point for bridge contracts. Each implementation is responsible for its access control logic. | ||
|
|
||
| ```solidity | ||
| function crosschainBurn(address _account, uint256 _amount) external; | ||
| ``` | ||
|
|
||
| ### Events | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding source/destination chain id & a unique message id to events would make crosschain data more easily usable. This ~may be a hard requirement for analytics, but hard to know without seeing further build out. This is necessary for joining messages across chains, to then see inflows/outflows by chain and routes. This gap is a main reason why you don't see this data for 3P bridges. Most sites do ~1-3 L2<>L2 bridges, then give up due to the high overhead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @MSilb7 ! Thank you for your suggestion. We have discussed your idea internally and agree that it has value. However, we couldn't find a minimalistic set of parameters to add to the event without making the current standard more opinionated:
We see significant value in adding I believe your idea has the potential to become a standard for bridge events. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On
My overall opinion is:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adding msg.sender to the event would make indexing significantly easier as we can now find all mints/burns associated with a specific bridge purely based on log data.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We just added |
||
|
|
||
| **`CrosschainMint`** | ||
|
|
||
| MUST trigger when `crosschainMint` is successfully called. | ||
|
|
||
| ```solidity | ||
| event CrosschainMint(address indexed _to, uint256 _amount) | ||
| ``` | ||
|
|
||
| Note: implementations might consider additionally emitting `Transfer(address(0), _to, _amount)` to be compliant with [ERC-5679](./eip-5679.md). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I strongly suggest making the Transfer events mandatory. ERC-20 is more relevant than ERC-5679 IMO, and in the former it's already specified as SHOULD (i.e., a strong recommendation):
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very good catch. Just pushed to modify this invariant. |
||
|
|
||
| **`CrosschainBurn`** | ||
|
|
||
| MUST trigger when `crosschainBurn` is successfully called. | ||
|
|
||
| ```solidity | ||
| event CrosschainBurn(address indexed _from, uint256 _amount) | ||
| ``` | ||
|
|
||
| Note: implementations might consider additionally emitting `Transfer(_from, address(0), _amount)` to be compliant with [ERC-5679](./eip-5679.md). | ||
|
|
||
| ## Rationale | ||
|
|
||
| The core design decisions behind this minimal interface are | ||
|
|
||
| - Bridge agnosticism. | ||
| - Extensibility. | ||
|
|
||
| **Bridge agnosticism** | ||
| This interface is designed so bridges, not tokens, contain the logic to process cross-chain actions. By maintaining this separation of concerns, token contracts remain simple, reducing their attack surface and easing auditing and upgradability. Offloading cross-chain complexities to bridge contracts ensures that tokens do not embed specific bridge logic. | ||
|
|
||
| By implementing the proposed interface, tokens can be supported by different bridge designs: | ||
|
|
||
| - Lock/unlock bridges can still operate and do not require any token modification. | ||
| - Burn/mint bridges can now use a universal and minimal token interface, so they will not need to introduce bridge-specific representations, improving cross-chain fungibility. | ||
|
|
||
| **Extensibility** | ||
| The minimal interface serves as a foundational layer upon which other standards can be built. | ||
| Token issuers or bridge contracts can extend functionality by adding features such as mint/burn limits, cross-chain transfer fees, and more without altering the core interface. | ||
|
|
||
| The interface is intentionally neutral and does not impose conditions on: | ||
|
|
||
| - **Access Control**: Token issuers determine who is authorized to call `crosschainMint()` and `crosschainBurn()`. | ||
| - **Zero Amount Calls**: Token issuers decide whether to allow or revert calls with zero amounts. | ||
|
|
||
| ### ERC-165 Interface | ||
|
|
||
| The inclusion of ERC-165 provides an additional security check for integrators. By providing the interface identifier through the `supportsInterface` method, callers can programmatically confirm that the token adheres to the `IERC7802` interface. | ||
| This verification ensures that the token supports both `crosschainMint` and `crosschainBurn` functions, preventing scenarios where only one function is implemented. Such incomplete implementations could lead to issues like users burning tokens to bridge out but being unable to mint them upon return, resulting in failed cross-chain actions. | ||
|
|
||
| It is important to note that this check can only be performed locally on the chain where the token contract resides. There is no inherent guarantee that the token on the receiving chain also supports the `IERC7802` interface. Ensuring cross-chain consistency of interface support is the responsibility of the bridge implementation. | ||
|
|
||
| ## Backwards Compatibility | ||
|
|
||
| This proposal is fully backwards compatible with [ERC-20](./eip-20.md). | ||
|
|
||
| As discussed in the Motivation section, a minimal, flexible cross-chain standard interface is necessary. The problem becomes larger as more tokens are deployed without a standardized format. | ||
|
|
||
| - Upgradable tokens can be upgraded to implement the new interface. | ||
| - Non-upgradable tokens cannot implement the interface on the token itself. They can still migrate to a standard-compliant version using a lockbox mechanism, as proposed by xERC-20. The idea is to lock non-mintable tokens and mint the same amount of interface-compliant tokens. The bridge contract can act as a lockbox on the native chain. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does xERC-20 have an ERC? If so, you should link it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It has an open PR to the ERC repo with assigned number 7281, but it has not been merged. If I mention the ERC-7281 in this ERC, the EIP validator asks for an internal link, which I can't reference at the moment. |
||
|
|
||
| Bridge contracts will also need an upgrade to integrate with the interface. Most popular bridges in terms of liquidity at the date are upgradable or use tokens that can be upgraded to point to new bridge contracts. | ||
|
|
||
| 1. Arbitrum One ($5.23B) | ||
|
0xParti marked this conversation as resolved.
Outdated
|
||
| 2. Portal Wormhole ($2.43B) | ||
| 3. Polygon PoS ($2.15B) | ||
| 4. OP Mainnet ($2.09B) | ||
| 5. Mantle ($983M) | ||
| 6. LayerZero OFTs ($465M) | ||
| 7. Omnibridge ($449M) | ||
| 8. Base ($350M) | ||
| 9. Scroll ($128M) | ||
| 10. zkSync ($77M) | ||
|
|
||
| Source: L2Beat (10/31/24) | ||
|
|
||
| ## Reference Implementation | ||
|
|
||
| ```solidity | ||
| // SPDX-License-Identifier: MIT | ||
|
0xParti marked this conversation as resolved.
Outdated
|
||
| pragma solidity 0.8.25; | ||
|
|
||
| import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
| import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | ||
|
|
||
|
|
||
| /// @title IERC7802 | ||
| /// @notice Defines the interface for crosschain ERC20 transfers. | ||
| interface IERC7802 is IERC165 { | ||
| /// @notice Emitted when a crosschain transfer mints tokens. | ||
| /// @param to Address of the account tokens are being minted for. | ||
| /// @param amount Amount of tokens minted. | ||
| event CrosschainMint(address indexed to, uint256 amount); | ||
|
|
||
| /// @notice Emitted when a crosschain transfer burns tokens. | ||
| /// @param from Address of the account tokens are being burned from. | ||
| /// @param amount Amount of tokens burned. | ||
| event CrosschainBurn(address indexed from, uint256 amount); | ||
|
|
||
| /// @notice Mint tokens through a crosschain transfer. | ||
| /// @param _to Address to mint tokens to. | ||
| /// @param _amount Amount of tokens to mint. | ||
| function crosschainMint(address _to, uint256 _amount) external; | ||
|
|
||
| /// @notice Burn tokens through a crosschain transfer. | ||
| /// @param _from Address to burn tokens from. | ||
| /// @param _amount Amount of tokens to burn. | ||
| function crosschainBurn(address _from, uint256 _amount) external; | ||
| } | ||
|
|
||
| contract CrosschainERC20 is ERC20, IERC7802 { | ||
| /// @notice Address of the TOKEN_BRIDGE contract that is allowed to mint/burn tokens. | ||
| address public immutable TOKEN_BRIDGE; | ||
|
|
||
| /// @notice Custom error for unauthorized access. | ||
| error Unauthorized(); | ||
|
|
||
| /// @notice Constructor to set the TOKEN_BRIDGE address. | ||
| /// @param _tokenBridge Address of the TOKEN_BRIDGE. | ||
| constructor(address _tokenBridge, string memory name, string memory symbol) ERC20(name, symbol) { | ||
| require(_tokenBridge != address(0), "Invalid TOKEN_BRIDGE address"); | ||
| TOKEN_BRIDGE = _tokenBridge; | ||
| } | ||
|
|
||
| /// @notice A modifier that only allows the TOKEN_BRIDGE to call | ||
| modifier onlyTokenBridge() { | ||
| if (msg.sender != TOKEN_BRIDGE) revert Unauthorized(); | ||
| _; | ||
| } | ||
|
|
||
| /// @notice Allows the TOKEN_BRIDGE to mint tokens. | ||
| /// @param _to Address to mint tokens to. | ||
| /// @param _amount Amount of tokens to mint. | ||
| function crosschainMint(address _to, uint256 _amount) external onlyTokenBridge { | ||
| _mint(_to, _amount); | ||
| emit CrosschainMint(_to, _amount); | ||
| } | ||
|
|
||
| /// @notice Allows the TOKEN_BRIDGE to burn tokens. | ||
| /// @param _from Address to burn tokens from. | ||
| /// @param _amount Amount of tokens to burn. | ||
| function crosschainBurn(address _from, uint256 _amount) external onlyTokenBridge { | ||
| _burn(_from, _amount); | ||
| emit CrosschainBurn(_from, _amount); | ||
| } | ||
|
|
||
| function supportsInterface(bytes4 interfaceId) external pure override returns (bool) { | ||
| return interfaceId == type(IERC7802).interfaceId || interfaceId == type(IERC165).interfaceId; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| Token issuers are responsible for controlling which contracts are authorized to call the `crosschainMint()` and `crosschainBurn()` functions. A buggy or malicious authorized caller could mint or burn tokens improperly, damaging token holders and disrupting integrations. | ||
|
|
||
| One method to minimize potential losses is introducing mint/burn limits, as proposed by xERC-20. These features are fully compatible with the proposed interface. | ||
|
|
||
| ## Copyright | ||
|
|
||
| Copyright and related rights waived via [CC0](../LICENSE.md). | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Interface" in an ERC title doesn't add a ton of information. Most ERCs contain some kind of interface.
How about:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with the suggestion of removing "interface" from the title. I'm not convinced about using "Permissioned", as that is not inherent to the interface (it could be permissionless). What do you think about something like "Token with Mint/Burn access Across Chains"?