Replies: 3 comments 11 replies
-
Do we actually allow duplicate note creation? Are these not rejected outright - and is this safe across epochs? As in, what happens if I create a new note with a duplicate nullifier where the original was created several epochs ago. Can the user not construct a new valid nullifier proof without including the original now? Or do nullifier proofs always include non-membership proofs for all prior epochs? |
Beta Was this translation helpful? Give feedback.
-
|
Looks good! I think this makes sense. Small questions/comments:
Just to double-check, to store 32 bytes we need 5 field elements, not necessarily two words, right? So we may be able to optimize this a bit more into 32 * 5 / 4 = 40 words? Not sure if it's easier to work with but it may reduce the cycle count of each transaction a bit - though not important to discuss now.
It would be nice if |
Beta Was this translation helpful? Give feedback.
-
As of now this is managed outside of the bridge by a separate GER contract on the L2 but no reason this couldn't be combined into the bridge contract so long as the Oracle knows how to interact with it. The contract stores a history of
On EVM chains the GER contract has some properties added when the contract is initialised containing the addresses of accounts allowed to add/remove GER entries from storage. The Oracle has the key for one of these accounts in it's keystore and will issue transactions to the contract to insert GERs to state. The link here has the implementation for the GER contract https://github.com/agglayer/agglayer-contracts/blob/main/contracts/v2/PolygonZkEVMGlobalExitRootV2.sol |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
In this post I'll describe the basics of how bridging via the AggLayer could work for Miden.
Unified bridge
Bridging on AggLayer works via the Unified Bridge (previously the LxLy bridge). The link has quite a bit of content, but the important concepts are:
Each L2 maintains a Local exit tree (LET) and the root of this tree is abbreviated as LER. LET is an append-only data structure represented by a Merkle tree. When we want to bridge something out of an L2, we need to append a node to the LET of that L2. The node we append needs to contain information about which asset we are bridging and where we bridging it to (destination network and address). There are several formats for doing so, the simplest of which is the
BridgeAssetMessageformat which looks like so:On the L1, there is a global exit tree (GET) and the root of this tree is abbreviated as GER. GET is a tree of trees. Leaves in this tree are LERs of all networks connected to the AggLayer. Besides the LERs, GET also contains a commitment to the mainnet exit tree (MET and MER respectively). This tree works like LETs, but it tracks exits from the L1 to L2s.
Once a node has been appended to a LET, claiming of bridged assets can be done by proving the existence of the node against the GER on the L1. Similarly, to move funds from L1 to L2, a node fist needs to be appended to MET, and then its inclusion needs to be proven on the L2 against GER (which L2s also maintain).
How could it work on Miden
To make this structure work on Miden, we'll need a few new contracts and a few new note types. To explain how it will work, we'll go through two flows - bridging from Miden to L1 and then from L1 to Miden.
Bridging from Miden to AggLayer
The high-level diagram of how to bridge assets from Miden to Agglayer looks like this:
First, we'll need a bridge account (i.e., something like
AggLayerBridgeaccount component). This account will need to keep track of the LET and the faucet registry. Since LET is an append-only data structure, we actually only need to keep track of the "frontier" of the tree - i.e., a set of nodes needed to append the next node. This is helpful because LET uses Keccak as a hash function and so it would have been very difficult for us to represent it using our SMTs. But because it is append-only, we only need to keep track of 32 nodes. Each of these nodes is 32 bytes and so, we'll need 2 word per node, or 64 words total. This can easily fit into simple storage slots.The faucet registry will maintain a list of faucets connected to the bridge. These could be stored in a storage map (or maybe storage array). Each connected faucet would need to satisfy a well-defined interface. For this we'll probably need to create something like
AggLayerFungibleFaucetaccount component.The exact interfaces of
AggLayerBridgeandAggLayerFungibleFaucetare TBD, but:AggLayerBridgewould expose something likebridge_assetprocedure. This procedure will takeASSET,destinations_network, anddestination_addressas parameters.AggLayerFungibleFaucetwould expose something likeconvert_assetprocedure. This procedure will takeASSETas a parameter and would return 256-bit amount and 20 byte token identifier for the asset. How exactly it'll do this is TBD.The overall flow for bridging out is then:
B2AGG) note and sends it to the bridge account.a. Makes an FPI call to the faucet to call its
convert_assetprocedure and get the amount/token address.b. Crates a
BridgeAssetMessageand appends it to LET it maintains.c. Sends a burn note with the original asset to the faucet account.
The transaction in step 1 would be a local transaction (i.e., executed by the user), but transactions in steps 2 and 3 would be network transactions. Although, transaction in step 3 could also be done locally - depending on how the faucet is defined. This also implies that the bridge account would need to be a network account, and the faucet account could be a network account or just public account.
Once the LET in the bridge account is updated, it will be propagated to the L1 and included into the L1s GET. We'll treat this process a black box for now. Once L1s GET is updated, the user will be able to claim their funds on the L1.
Bridging from AggLayer to Miden
The digram for bridging from AggLayer to Miden is a bit more complicated and looks like this:
Here we have 2 off-chain components that would do the following:
The high-level flow is then like this:
MAX_INPUTS_PER_NOTE(which is 128) - so, we'll probably need to bump this up.a. As a part of this FPI call, the bridge verifies that the request is coming from a registered faucet. This will ensure that random faucets can't interact with the bridge.
b. If the proof verifies, the faucet would issue our regular
P2IDnote with the newly minted asset. ThisP2IDnote would need to be generated deterministically - i.e., if someone tries to claim it again the exact same note will be generated again. This will naturally prevent ability to "double-claim" the bridged asset (because all such duplicate notes would have the same nullifier and thus, only one of such notes could be consumed).P2IDnote to get the asset.The transaction ins step 3 would need to be a network transaction. Transactions in steps 2 and 4 would be local transactions, and the type of transaction for step 1 is TBD.
New contracts
To summarize new contracts we'll need to support all of the above functionality:
AggLayerBridge- maintains LET and GERs to facilitate bridging. Also, has a registry of all registered faucets.AggLayerFungibleFaucet- maintains information about how to convert Miden assets into AggLayer assets, and provides functionality for claiming bridged assets.B2AGG(Bridge-to-AggLayer) note which is sent to theAggLayerBridgeaccount when the user wants to bridge assets out of Miden.BURNnote which can be sent to a faucet to burn the assets contained in this note (the faucet must be the issuer of the assets).AGGCLAIMnote which is sent the the claim manager (or the user) to anAggLayerFungibleFaucetaccount to claim the funds sent into Miden.Open questions:
Beta Was this translation helpful? Give feedback.
All reactions