taiko-mono icon indicating copy to clipboard operation
taiko-mono copied to clipboard

feat: no ETH premint on L2

Open dantaik opened this issue 2 years ago • 4 comments

Describe the feature request

Ethereum Shanghai fork will allow staking withdrawal. ETH will be topped directly to user's Ether balance without going through transactions. We may want to use that same mechanism to replace the Bridge's current approach.

See https://eips.ethereum.org/EIPS/eip-4895

dantaik avatar Feb 18 '23 03:02 dantaik

With EIP 4895, each Withdrawal is a tuple of 4 items:

  • a monotonically increasing index, starting from 0, as a uint64 value that increments by 1 per withdrawal to uniquely identify each withdrawal
  • the validator_index of the validator, as a uint64 value, on the consensus layer the withdrawal corresponds to
  • a recipient for the withdrawn ether address as a 20-byte value
  • a nonzero amount of ether given in Gwei (1e9 wei) as a uint64 value.

Our L1-to-L2 Ether transfer shall be saved in to a queue of Withdrawal object:

struct Withdrawal {
uint64 index;
uint64 validaorId; // maybe we can get rid of this and use a constant value 1
address receipient;
uint64 amount
}

Assuming each L2 block must process up to 10 withdrawals, then on L1, we may split the queue into:

uint64 nextWithdrawalToInclude;
Withdrawal[] withdrawals;

function proposeBlock(BlockMetadata memory meta) {
    ...
    meta.withdrawalRoots = calculateWIthdrawalRoots(maxWithdrawals);
    ...
}

function calculateWIthdrawalRoots(uint256 maxWithdrawals) returns (bytes32) {
    // we calculate the root, which may be pretty expensive. If it is indeed the case,
    // we can calculate a kecack hash of the withdrawal slice and verify the hash
    // matches the withdrawalsRoot using a ZKP 
}

The python code for calculateWIthdrawalRoots is like this;

def compute_trie_root_from_indexed_data(data):
    trie = Trie.from([(i, obj) for i, obj in enumerate(data)])
    return trie.root

dantaik avatar Apr 09 '23 07:04 dantaik

Created this PR for discussion https://github.com/taikoxyz/taiko-mono/pull/13577. This is to me a very priority.

dantaik avatar Apr 09 '23 07:04 dantaik

If we want to use the same mechanism as the beacon chain push withdrawals, we need:

  • a Withdrawals queue / Bridging queue
  • A cheap way to "push" the withdrawals to the L2 contract (JSONRPC methods?)
  • A way to verify the withdrawals on L1 so that L2 doesn't need to prove anything and mint trustlessly (WithdrawalsRoot)
  • A vault to hold the bridged ETH on L1 (?) (EtherVault)

The mechanism is automatic for EIP4895, the protocol sweeps the set of all validators and checks that they have a flag enabled and builds the queue accordingly. They can't set custom amounts, so we'll have to do it a bit differently.

It is also completely trustless, the verification is handled on beacon chain before the Withdrawal is pushed to the execution layer, probably verify the WithdrawalsRoot.

RogerLamTd avatar Apr 14 '23 07:04 RogerLamTd

Lets use the following terms for clarity:

  • Ether Deposit (Eth deposit for short): this is the ETH2 withdrawal-style deposit of Ether from L1 to L2 (note that this is no counterparty ETH Withdrawal from L2 to L1 using the same mechinism)
  • L1-to-L2 Bridge Ether Transfer (L1toL2 transfer in short)
  • L2-to-L1 Bridge Ether Transfer (L2toL1 transfer in short)

Without Ether premint on L2, our bridge and third party bridges will all work since Ether Deposit will mint new Ether on L2. Once accounts on L2 has Ether, they can be withdrawn by using L2toL1 transfers. Once these L2toL1 transfers are popular, L1toL2 transfer will be enabled. But there is a restriction:

$$\sum(L1toL2Transfer) \le \sum(L2toL1Transfer)$$

If users really want to deploy large amount of Ether using the bridge, we need premint Ether as a liquidity buffer on L2. Unless we don't do it at all, otherwise, preminting what we preminted on alpha-2 testnet seems to be fine.

dantaik avatar May 08 '23 10:05 dantaik