-
Notifications
You must be signed in to change notification settings - Fork 89
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
Initial draft of Alligator Interop spec #285
base: main
Are you sure you want to change the base?
Changes from 3 commits
b9725e2
32564b7
c83ec39
7d28a16
e34a7ad
5046a5b
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,136 @@ | ||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
**Table of Contents** | ||
|
||
- [Overview](#overview) | ||
- [Interface](#interface) | ||
- [Core Functions](#core-functions) | ||
- [Diagram](#diagram) | ||
- [Implementation](#implementation) | ||
- [Backwards Compatibility](#backwards-compatibility) | ||
- [Security Considerations](#security-considerations) | ||
|
||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
||
# Overview | ||
|
||
The goal of this specification is to allow interoperability between the base and superchains for that use the [`Alligator`](alligator.md) predeploy. This allows the support of the | ||
subdelegation flow with for the [`GovernanceToken`](gov-token.md) by making a few changes to the existing interface for cross-chain message passing as it pertains to the checkpoint state. | ||
|
||
## Interface | ||
|
||
### Core Functions | ||
|
||
```solidity | ||
function afterTokenTransfer( | ||
address src, | ||
address dst, | ||
uint256 amount | ||
) external | ||
``` | ||
|
||
In addition to performing it's standard functionality this method will now use the `L2ToL2CrossDomainMessenger` to send a message to a new method on the `Alligator` contract, `afterTokenTransferInterop`. It will ensure prior to doing so that the `chainId` is not OP Mainnet i.e. 10(0xa). Moreover, it will still handle a check that both address have been migrated using | ||
the new storage field and update the voting power of the delegate. | ||
|
||
```solidity | ||
function afterTokenTransferInterop( | ||
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 we just add this to 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. Done, updates now only happens if the contract is deployed on OP mainnet |
||
address src, | ||
address dst, | ||
uint256 amount | ||
) external | ||
``` | ||
|
||
The new function that will be added to the `Alligator` contract will process the interop messages being sent by the `afterTokenTransfer` method. The only address that can call | ||
this method is the `L2ToL2CrossChainMessenger`. Furthermore, it will check that the sender of this message is in fact another OP token with the same address, which is assumed since the | ||
goverance token is a predeploy. Given that messages are received from other tokens that exist on the superchain, an additional check needs to be performed that ensures we are on OP | ||
mainnet by checking the `chainId` before updating the checkpoints for the delegate voting power. | ||
|
||
## Diagram | ||
|
||
```mermaid | ||
sequenceDiagram | ||
participant delegate | ||
participant AlligatorSuperChain as AlligatorSuperChain (Chain A) | ||
participant AlligatorOPMainnet as AlligatorOPMainnet (Chain B) | ||
participant Inbox as CrossL2Inbox | ||
participant Messenger_A as L2ToL2CrossDomainMessenger (Chain A) | ||
participant Messenger_B as L2ToL2CrossDomainMessenger (Chain B) | ||
|
||
delegate->>AlligatorSuperChain: afterTokenTransfer(src, dst, amt) | ||
AlligatorSuperChain->>Messenger_A: sendMessage(nativeChainId, message) | ||
Messenger_A->>Inbox: executeMessage() | ||
Inbox->>Messenger_B: relayMessage() | ||
Messenger_B->>AlligatorOPMainnet: afterTokenTransferInterop(src, dst, amount, chainId) | ||
``` | ||
|
||
## Implementation | ||
|
||
```solidity | ||
function afterTokenTransfer( | ||
address src, | ||
address dst, | ||
uint256 amount | ||
) external { | ||
if (src != dst && amount > 0) { | ||
if (src != address(0)) { | ||
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount); | ||
emit DelegateVotesChanged(src, oldWeight, newWeight); | ||
} | ||
|
||
if (dst != address(0)) { | ||
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount); | ||
emit DelegateVotesChanged(dst, oldWeight, newWeight); | ||
} | ||
|
||
uint256 nativeChainId; | ||
assembly { | ||
nativeChainId := chainid() | ||
} | ||
|
||
if (nativeChainId != uint256(10)) { | ||
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. This is not going to be scalable as every token transfer on a remote chain will require a relayer to send a transaction on op mainnet. This means gov will need to front the costs here because nobody else has the incentive to do so. Wondering if there is a way that we can:
Going to brainstorm a bit on this |
||
L2ToL2CrossDomainMessenger.sendMessage({ | ||
_destination: nativeChainId, | ||
_target: address(this), | ||
_message: abi.encodeCall(this.afterTokenTransferInterop, (src, dst, amount)) | ||
}); | ||
} | ||
} | ||
} | ||
|
||
function afterTokenTransferInterop( | ||
address src, | ||
address dst, | ||
uint256 amount | ||
) external { | ||
require(msg.sender == address(L2ToL2CrossChainMessenger)); | ||
require(L2ToL2CrossChainMessenger.crossDomainMessageSender() == address(this)); | ||
|
||
uint256 nativeChainId; | ||
assembly { | ||
nativeChainId := chainid() | ||
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 do |
||
} | ||
|
||
require(nativeChainId == uint256(10)); | ||
|
||
if (src != address(0)) { | ||
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount); | ||
emit DelegateVotesChanged(src, oldWeight, newWeight); | ||
} | ||
|
||
if (dst != address(0)) { | ||
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount); | ||
emit DelegateVotesChanged(dst, oldWeight, newWeight); | ||
} | ||
} | ||
``` | ||
|
||
The contract may support a function to get the chainId or another modifier to prevent the Interop function to be called outside of OP mainnet. | ||
|
||
## Backwards Compatibility | ||
|
||
Previous instances of `Alligator` will not be able to interface with the OP mainnet contract given that they do not support the cross-chain message passing. However, the existing state | ||
of voting power on the superchain shall remained unchanged. | ||
|
||
## Security Considerations | ||
|
||
We must ensure that that both the `GovernanceToken` and `Alligator` use the same address across all chains. |
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.
One common misconception is that each chain is called a superchain, but really the superchain is made up of individual chains. What do you mean the base here?
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.
Explicated the use of other OP chains that are not mainnet and their interaction with the
Alligator
contract