Pre-Proposal: L1 <> L2 Migration Workflow

Motivation

Today, the protocol contracts are deployed on L1 Ethereum and the gas fees for transactions depend on the limited blockspace of L1 which is currently consistently being filled by other popular applications (i.e. NFTs, DeFi, etc.) resulting in high gas fees. A reduction in the gas consumption of contracts can only help so much and in order to reduce the transactions fees by an order of a magnitude the contracts will likely need to be deployed to a L2 with substantially lower gas prices. An important question that needs to be answered in order to move the contracts into a L2 is: how will users move their staked LPT?

Both delegators and orchestrators need to wait through a 7 round (~6-7 day) unbonding period in order to withdraw their staked LPT. As a result, as is, the migration process to another domain would present a lot of friction for users and could take a long time due to the unbonding period requirement.

Ideally, the migration process could have the following properties:

  • Users can submit a single transaction on L1 to migrate staked LPT to L2 contracts
  • The supply of LPT on both L1 and the L2 is controlled by the same monetary policy

This post outlines ideas for a L1 <> L2 migration that would work similarly to how Uniswap LPs migrate liquidity from one version of Uniswap to another and that would support inflationary LPT minting on L2 while still allowing bi-directional transfers of LPT between L1 and L2.

L1 → L2 stake migration workflow

The BondingManager contract on L1 Ethereum can be upgraded with the following function:

// L1
interface IBondingManager {
    function migrateStake(address _delegator) external returns (uint256);
}

The migrateStake() function can only be called by a Migrator contract on L1 to instantly unbond (without an unbonding period) and withdraw the delegator’s staked LPT into the Migrator contract. If the specified delegator is an orchestrator (which is a self-delegated delegator), the orchestrator is deactivated & unregistered in the BondingManager.

// L1
contract BondingManager {
    function migrateStake(address _delegator)
        external
        autoClaimEarnings
        onlyMigrator
        returns (uint256)
    {
        uint256 stake = delegators[_delegator].bondedAmount;

        // Zero out relevant storage values
        // ...

        // Move LPT to Migrator
        minter().trustedWithdrawTokens(address(migrator()), stake);

        return stake;
    }
}

The migrateStake() function will not touch a delegator’s ETH fees. The delegator will still be able to withdraw its ETH fees on L1 using the withdrawFees() function on the BondingManager.

The Migrator contract is responsible for escrowing LPT into a gateway contract that bridges L1 with the L2 and also submitting a message that can be executed on L2 to stake the LPT in the staking contract deployed there.

// L1
contract Migrator {
    IGateway public immutable gateway;
    ILivepeerToken public immutable token;
    IBondingManager public immutable bondingManager;

    function migrate(address _destOrchestrator)
        external
    {
        // Pull staked LPT from BondingManager
        uint256 stakeToMigrate = bondingManager.migrateStake(msg.sender);
        // Approve gateway to pull LPT from this contract
        token.approve(gateway, stakeToMigrate);
    
        // Call gateway to:
        // - Escrow LPT in gateway
        // - Pass message to mint LPT on L2 and stake for
        // the delegator in the staking contract there
    }
}

The _destOrchestrator argument offers the caller flexibility in specifying the orchestrator address that migrated stake should be delegated to on L2. _destOrchestrator may be different from the caller’s current orchestrator on L1. The ability to specify a different orchestrator when migrating stake will also be important if the current orchestrator on L1 has not yet migrated its stake to L2. In this scenario, a delegator that wants to migrate to the L2 likely would want to delegate its stake to a different orchestrator that has already migrated to the L2.

Users will call the migrate() function on the Migrator in order to execute the migration to the destination chain.

The L2 staking contract could support the following function:

// L2
interface IStakingManager {
    function stakeFor(
        address _delegator,
        address _orchestrator,
        uint256 _amount
    )
        external;
}

In contrast with the L1 BondingManager, which only allows LPT to be staked and delegated by the msg.sender in the bond() function, the L2 StakingManager would allow LPT to be staked and delegated on behalf of a specified address that does not have to be msg.sender. This function allows the Migrator to stake and delegate LPT in the StakingManager on behalf of a user that is migrating to the L2.

// L2
contract Migrator {
    IStakingManager public immutable stakingManager;

    function migrate(
        address _delegator,
        address _orchestrator,
        uint256 _amount
    )
        external
        onlyBridge
    {
        stakingManager.stakeFor(_delegator, _orchestrator, _amount);
    }
}

The Migrator on the L2 is just responsible for calling the stakeFor() function on the BondingManager to stake LPT on behalf of the user that triggered a migration on L1.

L2 inflationary minting

A remaining question is how to handle the fact that the LPT escrowed in a L1 gateway will not be able to cover all the LPT that could be burned on a L2 if inflationary minting is supported on the L2. One way to address this by allowing a LPT burn in the L2 gateway to trigger LPT minting on L1.

Note that in practice the L1 and L2 gateways may be composed of multiple contracts. For example, in Arbitrum there could be arbitrary message passing bridge, a ERC-20 token bridge to move liquid LPT between L1 & L2 and a staked LPT bridge to move staked LPT from L1 to L2.

L2 workflow

The minting authority for the L2 LPT contract is set to a Minter contract - the only address that can mint new L2 LPT is the Minter. The Minter can delegating minting authority to one or many other addresses allowing the addresses to trigger minting through the Minter. In this workflow, the Minter delegates minting authority to:

  • The L2 gateway
  • StakingManager

The L2 gateway will trigger minting of L2 LPT through the Minter when an equivalent amount of L1 LPT was escrowed in the L1 gateway.

The StakingManager will trigger minting of L2 LPT through the Minter when LPT inflationary rewards are minted for staked orchestrators.

If a user wants to move back to L1, they can burn L2 LPT in the L2 gateway.

L1 workflow

The minting authority for the L1 LPT contract is also set to a Minter contract similar to on L2. On L1, the Minter only delegates minting authority to the L1 gateway. So, new L1 LPT can only be minted when triggered by an L2 message. Note this means that the L1 LPT minting mechanism completely trusts the L2 minting mechanism - if there are any bugs/issues with the L2 minting mechanism then there is nothing stopping the minting of excess L1 LPT (outside of pause mechanisms built-in to the Minter which are outside of the scope of this post).

After a user burns L2 LPT in the L2 gateway, a message is passed to the L1 gateway.

Let’s assume that X L2 LPT was burned.

If the L1 gateway LPT escrow >= X, then X L1 LPT is transferred to the user on L1.

If the L1 gateway LPT escrow < X, then the L1 gateway will mint X - L1 gateway LPT escrow L1 LPT which is sent into the L1 gateway escrow. Now, with a topped off escrow, the L1 bridge will transfer X L1 LPT to the user on L1.

Next Steps

  • Create a full prototype implementation iterating on these ideas as is needed (already in-progress using Arbitrum as the destination L2)
  • Decide on the destination L2 (Optimism, Arbitrum, etc.)
  • If these ideas are validated in a prototype implementation and there is community support, create a draft LIP
2 Likes

An alternative to the “L2 inflationary minting” design in the OP:

Instead of supporting minting on L2, minting could just be supported on L1 and any minted tokens would be migrated via a gateway to the L2 Minter. A reward transaction would still be submitted by orchestrators on L2 during each round in order to distribute rewards to the orchestrators and its delegators, but the reward transaction would not mint any tokens since tokens have already been minted and migrated to the L2 Minter from L1. In order to reduce L1 tx costs, rewards could be minted and migrated from L1 less frequently. For example, suppose a round on L1 is 7 days and a round on L2 is 1 day. Rewards could be minted and migrated at the beginning of every L1 round and those rewards could be distributed in each of the following 7 L2 rounds. Rounds on L1 and L2 could both be defined in terms of L1 blocks to make it easier to reason about how L1 and L2 round progression align with each other.

Since the rewards available for a round are determined by the current inflation rate which depends on the total staked supply vs. the total supply, L1 would need a way to determine the staked supply on L2. At the moment, there is not an easy way to read state from L2 on L1. In an optimistic rollup, an L1 contract can only determine if L2 state is valid after a delay. In a zk rollup, an L1 contract can determine if L2 state is valid immediately after the ZKP is validated by the L1 verifier contract, but there is still some time before EVM compatible zk rollups will be production ready. A workaround to this problem could be to use an oracle to report the L2 staked supply to L1 at regular intervals. Even if an optimistic rollup is used, an oracle can validate the L2 chain state off-chain. In the short term, the oracle address(s) that can report L2 staked supply to L1 can be determined via governance. A subsequent improvement could be to use an oracle network such as Chainlink.

A sketch of how this could work in practice:

  • An oracle reports the L2 staked supply to L1 at regular intervals and the value is cached
  • When a new round is initialized on L1, calculate the total staked supply and total supply across L1 + L2 and use the result to determine the current inflation rate. Then, mint 100% of rewards for the round based on the current inflation rate and send them to the L2 Minter via the gateway
  • On L2, track the amount of rewards that have been migrated from L1
  • On L2, calculate the amount of rewards that are available in each round based on the total rewards that have migrated and the number of L2 rounds that the rewards should be distributed over i.e if there are 700 rewards and 1 L1 round = 7 L2 rounds distribute 700 / 7 = 100 rewards in each L2 round

Pros of this approach:

  • No need for a special gateway between L1 and L2. The “L2 inflationary minting” design would likely need a special gateway where LPT can only move through the special gateway to ensure that L1 LPT can be minted for newly inflationary L2 LPT that is being moved to L1
  • There should be less contract code required on L1 and L2 to support this
  • Reduces scope of impact of L2 bugs to incorrect LPT distribution on L2 as opposed to excess LPT being minted (since no LPT is minted on L2)

Cons of this approach:

  • Incur L1 tx costs when rewards need to be minted. This can be countered somewhat by minting and migrating rewards less often
  • Requires an oracle to report L2 state to L1
1 Like

With the cost of gas fees any one under 10k stake is doing reward calls for a loss. (this makes the top 32 orchestrators profitable or break even) which means majority of the bottom orchestrators are either taking a loss or transcoding for fees exclusively.

Taking steps to reduce the reward call fees to as minimally as possible, in my opinion, should be a high priority, you’d be activating the remaining orchestrators in the top 100 and allow for a more fair distribution of delegator stake as delegators wont distribute to people who aren’t making calls.

Even at 1 reward call per week which would run about 50-100$ in gas fees would still require orchestrators to have closer to 2k LPT staked to break even on it. Although if the upgrade aligns with the release of ETH2.0 maybe gas fees would be drastically less but it would never get to the level at which people without significant stake can do reliable reward calls without taking a loss.

Keeping LPT reward calls in L2 where fees would be drastically lessened would be ideal to a more consistent inflationary call schedule across majority of the orchestrators and their delegators.

1 Like

Keeping LPT reward calls in L2 where fees would be drastically lessened would be ideal to a more consistent inflationary call schedule across majority of the orchestrators and their delegators.

For clarification, in both of the options presented thus far for handling inflationary minting, reward calls by orchestrators would take place on L2. The main difference with the second option is that LPT would be minted for all orchestrators/delegators for a round on L1 (this could be triggered by any account when a round is initialized on L1), transferred to L2 and then each reward call by an orchestrator would claim a portion of the LPT that was transferred over to be distributed between itself and its delegators.

In summary:

  • In the first option, reward calls mint LPT and distribute rewards to an orchestrator and its delegators
  • In the second option, reward calls just distribute rewards to an orchestrator and its delegators because the LPT has already been minted

So, the bulk of the expensive logic in reward calls would be executed on L2 regardless of which option is used.

2 Likes

Thank you for clarifying that makes more sense!

L2 Minting with custom bridge

Overview

This design tries to accomplish a full transtition of the Livepeer protocol to a layer-2 solution such that the canonical protocol and Livepeer token lives on a layer-2 solution.

This is a different paradigm than what we’ve seen so far from several protocols who have migrated to rollup solutions (e.g. Balanace, Uniswap, …). For these systems their canonical token contracts still live in Ethereum mainnet. When we consider this paradigm in terms of token balances it means that the supply of a derivative token on another layer will always be equal to what is locked in the token bridge to that layer from the Ethereum mainnet side. This leads us to the high-level workflow for the standard token bridges: funds are escrowed/released in the L1 bridge contract and minted/burnt on the L2 they are transferred to.

In the case of Livepeer however if the entire protocol moves to L2 and inflationairy minting also happens on L2 we have to basically reverse this paradigm. In this case we can consider Layer 1 Ethereum as just “a layer” to which funds can be transferred and spent. However the supply on L1 Ethereum for the derivative Livepeer token will never exceed what is locked to said layer on the L2 side.

L2 => L1 (Including rewards)

  1. User earns LPT rewards on L2 on top of his principal staked amount
  2. User unstakes and withdraws funds from the L2 BondingManager.
  3. User deposits funds into the L2 side of the custom token bridge
    3.1. Funds are transferred from User to the L2 token bridge
    3.2. Funds are escrowed in the L2 token bridge
    3.3. The L2 token bridge adds the amount deposited to the balance for the corresponding L2 token contract
    3.4. A finalizeDeposit message is created and sent into the message brokers
  4. When the message is relayed to L1, the L1 messenger will finalize the deposit on L1
  5. Derivate LivepeerToken' is minted for the user that initialised the deposit

L1 => L2

This workflow can not take place without first having moved funds from L2 to L1

  1. User calls withdraw() on the L1 Token bridge to initiate a transfer of L1 funds back to L2
  2. The amount to send across is burnt from the user’s balance
  3. A finalizeWithdraw message is created and sent into the message brokers
  4. When the message is relayed to L2, the L2 messenger will release escrowed funds to User

Assumptions

  • The initial migration to L2 is left out of scope
  • The current Livepeer token contract on mainnet will eventually become stale once all LPT has been migrated over to L2.
  • Going forward on Ethereum mainnet a new token contract LivepeerToken' will be used.
  • The Livepeer token contract on L2 will be the canonical token contract
  • The monetary policy and inflation is purely managed on L2 and based on the staked funds and total supply on L2 solely.

Pros

  • No usage of oracles
  • canonical protocol on a single chain
  • No changes to monetary policy required due

Cons

  • Monetary policy doesn’t live on the L1 which could be considered most secure, although optimistic roll-up security models come very close to mainnet today
  • Incompatibility with the standard token bridges (L2 tokens would be burnt rather than escrowed)
1 Like

I’ve created two draft LIPs based on the ideas in this thread and I’m including the links to their respective discussion threads below:

I opted to move forward with the L1 minting design for LIP-74 for now, but definitely open to feedback and iteration/updates - @NicoV I will review and follow up on your proposed design as well.

1 Like

Thanks for sharing this!

inflationairy minting also happens on L2

At the moment, I’m wary of immediately moving inflationary LPT minting into a specific L2 because at the moment all EVM compatible L2s are relatively immature and have only been in production for a short period of time. So, I think it is worthwhile to take some precautions when migrating protocol logic to L2. If inflationary minting takes place on L1, then the scope of impact of an L2 bug is limited to the incorrect distribution of LPT rewards and ETH fees. If inflationary minting takes place on L2, then the scope of impact of an L2 bug is expanded to the incorrect inflation schedule of LPT (i.e. excessive burning and/or minting). The latter is more disruptive and more difficult to recover from. With that being said, starting off with inflationary minting on L1 does not preclude the possibility of eventually moving inflationary minting on L2 given more time for the L2 to become battle tested and given additional security mechanisms that can reduce the scope of impact of L2 bugs.

Going forward on Ethereum mainnet a new token contract LivepeerToken' will be used.

The introduction of a new version of LPT seems unnecessary and seems like it would increase user confusion given that it is likely that a non-zero supply of LivepeerToken and LivepeerToken' would exist simultaneously on L1. I think the inflationary minting design in the OP would support minting on L2 and bi-directional LPT bridging between L1 & L2 with just a single version of LPT in each domain.

2 Likes

I do like the first option (minting and distributing on L2) more since it looks less patched together and does not require an oracle. But I do get your security concerns regarding giving complete control to the L2 minter.
Have you already talked with the L2 teams regarding this? Would be interesting to hear their opinion and they might have a third option?

2 Likes

Would L2 help move away from the current probabilistic micropayment protocol?

Possibly. The lower tx costs of a L2 could potentially make other micropayment designs more attractive. For example, we also considered using payment channels early on, but at the time one of the concerns with payment channels was the tx costs for re-allocating funds into different channels (the tx costs are either borne by the payer or the router that facilitates payments between the payer and the payee). With lower tx costs for re-allocating funds into different channels, this design may be worth re-visiting along with other designs that have emerged since the initial deployment of the probabilistic micropayment protocol.

1 Like

But I do get your security concerns regarding giving complete control to the L2 minter.

Recently, I’ve become less concerned about this and more in favor of just having protocol inflation on L2 because:

  • In order to support bridging LPT from L1 to L2, there is already a form of minting that happens - the contract that is authorized to mint LPT on L2 just happens to be the L2 gateway of the bridge. Supporting protocol inflation on L2 would just be a matter of authorizing an additional contract to mint LPT on L2 i.e. the protocol Minter contract. If we assume that the protocol Minter contract is the same one that is used on L1 today, then the additional security risk of using it for protocol inflation on L2 feels minimal.
  • Transferring a batch of LPT to L2 for distribution in each round requires some re-architecting of the contracts and also some considerations around what to do with LPT from that batch if an orchestrator does not call reward in that particular round (today, the LPT is simply not minted, but if the LPT is first minted on L1 then transferred to L2 then that LPT already exists).
  • From a security POV, if there is an invalid state update (if the fraud proof system for an oRU breaks for whatever reason) on L2 then in order to protect users it still comes down to protecting the escrowed LPT on L1 for the bridge and making sure that users can be given access to that LPT if needed. The dispute period of an oRU actually becomes useful here because during that period monitoring tools that validate state on L2 (i.e. by running a L2 node) can alert the community of an invalid state update that was not caught by a fraud proof allowing intervention to prevent the escrowed LPT from being withdrawn.

Have you already talked with the L2 teams regarding this? Would be interesting to hear their opinion and they might have a third option?

Briefly in the past and my takeaway was that the design space is a bit more limited given an already existing L1 token (as opposed to the scenario where you’re creating a completely new L1 token that can have functionality tailored for bridging with L2) which is what resulted in the presentation of the two approaches from earlier in this thread.

But, we’re also currently looking to get feedback on the latest designs as well.