LIP-73: L2 Stake Migration

This is the discussion thread for LIP-73: L2 Stake Migration. The LIP is currently a draft and is accepting community feedback as the content continues to be iterated on.

Note: The LIP currently does not specify a particular L2, but by the time it enters Last Call the expectation is that the LIP will be updated to reference a particular L2. The current implementation track that is helping to inform this LIP is using Arbitrum.


Does the L2 migration also migrate over the voting process for LIPs?

Question on the L2 migration - I understand that Arbitrum is being used during the evaluation.

Are Optimism and zksync also being evaluated as potential options?

And can anyone shed any light on how a decision will be made as to which network will be proposed in the last call for the LIPs?

Exciting times! Keep up the great work!


I think it could make sense to migrate the poll voting system to L2 such that poll contracts are created on L2 (lower transaction cost for poll creation as well as voting) and stake on L2 is used to determine the weight of votes (which could make sense if we expect a large portion of stake to migrate to L2). Planning on sharing a governance specific post soon.

And can anyone shed any light on how a decision will be made as to which network will be proposed in the last call for the LIPs?

Planning on sharing a post describing the framework that the team has been using to evaluate/consider existing L2s and that could be used to evaluate/consider future L2s soon!

A few updates I’m planning on making to the current proposal:

  • Support specifying an amount of stake to migrate in the L1 Migrator instead of migrating all stake. This feature can be useful for users that have a large amount of stake and that wish to take precautions while migrating stake to L2 by starting with a smaller amount. An app that is integrated with the L1 Migrator can still set the default amount to an account’s entire stake while also giving the user the option to change the amount.
  • Support authorizing migrations using EIP-712 signatures as a replacement for the opt-out mechanism that is described in the current proposal. This feature makes it easier for orchestrators to use a web UI (i.e. the explorer) for migration without exporting/importing their local keystore files (which store their encrypted private key) since they can sign a message within the CLI and provide the signature in the web UI. A user could either submit a migrate tx directly using their delegator account or they could sign a message with a deadline (the last time at which the signature can be submitted on-chain) and any address could then submit the signature on-chain.

Find below a sketch of the code to support these features which is pretty similar to the OpenZeppelin EIP-2612 Permit minus a few tweaks:

struct MigrateMsg {
    // Address of delegator to migrate stake
    address srcDelegator;
    // Address of delegator to receive migrated stake
    address dstDelegator;
    // Address of orchestrator to delegate migrated stake to
    address dstOrchestrator;

    // Hints for updating the position of dstOrchestrator in the pool
    address dstOrchestratorNewPosPrev;
    address dstOrchestratorNewPosNext;

    // Amount of stake to migrate
    uint256 amount;
    // Deadline for signature to be used for migration
    // Optional: Only required if sig is set
    uint256 deadline; 
    // Signature to authorize migration
    // Optional: Only required if msg.sender != srcDelegator
    bytes sig;

mapping (address => uint256) public nonces;

function migrate(MigrateMsg memory _msg) external {
    if (_msg.sig != bytes(0)) {
        // Use nonce to generate MigrateMsg EIP-712 hash
        nonces[_srcDelegator] += 1;
        // Recover signer from signature
            block.timestamp <= _msg.deadline,
            "expired deadline"
            signer != _msg.srcDelegator,
            "invalid signer"
    } else {
            msg.sender != _msg.srcDelegator,
            "invalid msg.sender"
    bondingManager.migrateStake(_srcDelegator, _msg.amount);
    token.approve(l1Gateway, _msg.amount);
    // Call gateway

Another realization I had while considering the implications of supporting specifying an amount of stake to migrate is that if the delegator address on L2 already has a delegate then a migration should not modify that delegate. Otherwise, an address on L1 could modify the delegate of another address on L2 during a migration. In practice, we can just ignore the dstOrchestrator argument of a migration message in the L2 Migrator if the dstDelegator already has a delegate in the L2 BondingManager.

Updated the LIP in this PR.

1 Like