Skip to content

L2 Vaults

Brecht Devos edited this page Feb 19, 2021 · 6 revisions

Different steps we can use to bring a lot of popular defi operations to L2 users for cheap by making use of the fact that most defi operations are directly represented by tokens (token <-> vToken, where vToken is a fixed balance token that is a share in a growing pool).

It's possible to first do 1) and then switch to 2) when we are ready. 3) is an additional improvement but may or may not make sense to do depending on how well 2) works.

1. Token <-> vToken order book

This could be a first and easy step because we don't have to really do anything. We let other users provide the liquidity and for us it's just another order book.

2. Token <-> vToken "swap"

A full order book is probably not the most efficient way to do things. It's also not really user friendly, people are used to just joining and exiting a pool with a simple deposit/withdraw and slippage parameter.

So the idea here is that we don't really use an order book. We allow people to buy/sell the vToken for some price within the slippage. And we make sure that the trade price is as close as possible to the actual price on L1.

By doing this we have a very simple mechanism with a single price where all joins and exits are automatically batched to a single surplus or deficit for the vToken. which we can show to users. We then have the following scenario's:

  • vToken deficit and a user wants to buy vToken: The deficit increases.
  • vToken deficit and a user wants to sell vToken: The deficit decreases (if amount < deficit) and the user can sell vTokens immediately.
  • vToken surplus and a user wants to buy vToken: The surplus decreases (if amount < surplus) and the user can buy his vTokens immediately.
  • vToken surplus and a user wants to sell vToken: The surplus increases.

This makes a lot of sense. People that want to buy vToken are directly matched to users that want to sell vToken. There are always people that want to enter a pool and people that want to exit the pool. These can be matched on L2 even without needing any dedicated liquidity providers. This is more like P2P/OTC trading where we just connect people that want to do the opposite operation.

The UI for this would indeed be very simply. It would basically be the general vault UI with deposit and withdraw, but we also show the surplus/deficit because that will decide if the user immediately gets his tokens or there will be a delay until someone shows up to be his counterparty.

Perhaps we can also incentive liquidity providers to help reduce the surplus/deficit somehow. E.g. every hour the deficit/surplus is non-zero for the Vault N LRC is added to the reward for anyone that can bring the deficit/surplus to 0. Seems much more efficient than liquidity mining on order books. In theory a very small reward should be sufficient, but I guess we'd have to wait and see.

Another similar idea is to let users doing to give extra "tips", as a kind of extra incentive to they can try to get their tokens quicker by paying a bit more than usual. This also works well together with 3) because we could do the L1 batched operation once the amount collected > the L1 gas cost no matter the actual size of the batch.

3. Token <-> vToken L1 batching

This is a fallback system on top of 2) we can use when we want to be able to process outstanding deficits/surpluses ourselves, without the need for any capital. We can do so by using something similar to flash loans on L2 and then use the funds extracted on L2 to do the token <-> vToken swap on L1 if needed. The reason not to use actual flash loans is that there is no guarantee the tokens we need are even available somewhere to loan from, and because we are on L2 we create the tokens out of thin air.

POC: https://github.com/Loopring/protocols/pull/2218

An example with ETH <-> yETH:

  • The result of 2. is that 100 ETH needs to be swapped to 100 yETH because users want to enter the yETH pool. So we know there are X orders open that trade between ETH <-> yETH and 100 ETH <-> 100 yETH is the batched result.
  • Problem: We need 100 yETH to make these trades happen.
  • Solution: Flash deposit 100 yETH to an our account on the exchange
  • Process all trades between ETH <-> yETH
  • We know have 100 ETH in our account
  • Withdraw this 100 ETH
  • Use this 100 ETH to get 100 yETH by depositing 100 ETH to the yETH pool and receive 100 yETH
  • Use the 100 yETH to repay the flash deposit

It's also possible to not use these flash deposits and do something more like the AMM pools where joining/exiting a pool is a special operation and we first transfer funds to an account so we can use those funds on L1 and then do another transfer back after the block has been processed with the swapped tokens. But as can you can see that will always be much more expensive than just using simple L2 trades which don't need any additional L1 work. Also by just doing trades the same signed order can be used in all scenario's (matched with another user on L2 or with L1 batching).

Risks

In the general case there are some small risks by doing this because the batched swap is done on L1 at the same time the block is submitted. And so the following could happen, although should be very low risk in general:

  • The swap call could fail for some reason. This would mean we don't have the necessary tokens to repay the flash loan. Depending on the reason (the pool has been closed for example) this could make it impossible for the block to ever be valid. Very low chance of this happening, but a possibility nonetheless.
  • We need to do the trades on L2 at some rate, but we don't know the exact rate until the L1 swap actually happens. Because the exchange rate between these token/vToken changes very slowly we can be sure this isn't a problem by always having a safety margin. This can also be completely solved by wrapping the token in another pool we fully control, but I don't think that will be necessary.

3.1 ETH <-> LP-X Vaults

Our AMM pools are also vaults, so we can use all of the above to make AMM joins/exits cheaper with the same mechanisms. What is a bit special about them is that the risks for using the flash deposits don't apply because we are always completely in control over all the contracts. We don't even have to do much on L1, just do all trades, then join/exit the pool, withdraw and repay the deposit flash.

Flash deposits other use cases

Flash deposits are basically flash loans on L2 so they allow whatever they allow on L1. But they could be used by any L2 user to do risk-free arbitrage without any capital because everything is 100% deterministic on L2. Like flash loans on L1, it's quite expensive but we could charge a large fee for API users for being able to use this.

Special cases

Most special cases can be handled by wrapping the "problematic" tokens:

  • aTokens
  • Tokens that get rewards in a different token
  • ....