-
Notifications
You must be signed in to change notification settings - Fork 115
feat(Agglayer): add scaled down quotient to CLAIM note NoteStorage
#2336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
46143c8
3c84da6
c71d9df
779ab24
a8238b6
5dd9c85
99bcee7
2d0a89a
3d45e7f
43cbcf3
049e8be
99161e3
3dc29f6
4c6289d
a5f3309
576f907
a8e35d3
a1a1c3d
359b3ef
1264d24
2288c0d
d9c309a
393ee03
3c3c29e
a926316
af29827
d6b9954
f9f2d57
d61f836
d51bed1
1388770
f200752
fc9ff91
0aef40d
1a3b8a3
8ebdc7b
2dfa097
1567d89
c1aec4d
193c618
a36bc67
2d2cb9b
dd83b50
cb920e7
4c5ccae
66bf679
05e323c
7f6e334
ea546bb
60ab0ae
2f5283a
4991976
329397e
04d29e3
6644bb6
570e92b
33611f6
87100a1
98c21a5
d75ce0f
89e75e9
a35183d
b22cb15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| [submodule "crates/miden-agglayer/solidity-compat/lib/forge-std"] | ||
| path = crates/miden-agglayer/solidity-compat/lib/forge-std | ||
| url = https://github.com/foundry-rs/forge-std | ||
| [submodule "crates/miden-agglayer/solidity-compat/lib/agglayer-contracts"] | ||
| path = crates/miden-agglayer/solidity-compat/lib/agglayer-contracts | ||
| url = https://github.com/agglayer/agglayer-contracts |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| exclude = ["crates/miden-agglayer/solidity-compat/lib/*"] | ||
|
|
||
| [formatting] | ||
| align_entries = true | ||
| column_width = 120 | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,5 @@ | ||
| [default] | ||
| extend-ignore-identifiers-re = [".*1st.*", ".*2nd.*", ".*3rd.*"] | ||
|
|
||
| [files] | ||
| extend-exclude = ["crates/miden-agglayer/solidity-compat/lib"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| use miden::agglayer::bridge_in | ||
| use miden::agglayer::asset_conversion | ||
| use miden::agglayer::eth_address | ||
| use miden::protocol::active_account | ||
| use miden::protocol::active_note | ||
| use miden::standards::faucets | ||
| use miden::protocol::note | ||
| use miden::protocol::tx | ||
| use miden::core::mem | ||
| use miden::core::word | ||
|
|
||
|
|
||
| # CONSTANTS | ||
|
|
@@ -14,8 +16,14 @@ use miden::core::mem | |
| # The slot in this component's storage layout where the bridge account ID is stored. | ||
| const BRIDGE_ID_SLOT = word("miden::agglayer::faucet") | ||
|
|
||
| # The slots where origin token address and scaling factor are stored | ||
| # AGGFAUCET_METADATA_SLOT_0: [tok0, tok1, tok2, tok3] | ||
| # AGGFAUCET_METADATA_SLOT_1: [tok4, scaling_factor, 0, 0] | ||
| const AGGFAUCET_METADATA_SLOT_0 = word("miden::agglayer::aggfaucet_metadata_0") | ||
| const AGGFAUCET_METADATA_SLOT_1 = word("miden::agglayer::aggfaucet_metadata_1") | ||
|
|
||
| const PROOF_DATA_WORD_LEN = 134 | ||
| const LEAF_DATA_WORD_LEN = 6 | ||
| const LEAF_DATA_WORD_LEN = 8 | ||
| const OUTPUT_NOTE_DATA_WORD_LEN = 2 | ||
|
|
||
| const PROOF_DATA_START_PTR = 0 | ||
|
|
@@ -31,8 +39,23 @@ const CLAIM_NOTE_DATA_MEM_ADDR = 712 | |
| const OUTPUT_NOTE_INPUTS_MEM_ADDR = 0 | ||
| const OUTPUT_NOTE_TAG_MEM_ADDR = 574 | ||
| const OUTPUT_NOTE_SERIAL_NUM_MEM_ADDR = 568 | ||
| const OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_0 = 548 | ||
| const OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_1 = 552 | ||
| const OUTPUT_NOTE_SCALED_AMOUNT_MEM_ADDR = 575 | ||
| const OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_0 = 552 | ||
| const OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_1 = 556 | ||
|
|
||
| const ORIGIN_TOKEN_ADDRESS_0 = 541 | ||
| const ORIGIN_TOKEN_ADDRESS_1 = 542 | ||
| const ORIGIN_TOKEN_ADDRESS_2 = 543 | ||
| const ORIGIN_TOKEN_ADDRESS_3 = 544 | ||
| const ORIGIN_TOKEN_ADDRESS_4 = 545 | ||
|
|
||
| const DESTINATION_ADDRESS_0 = 547 | ||
| const DESTINATION_ADDRESS_1 = 548 | ||
| const DESTINATION_ADDRESS_2 = 549 | ||
| const DESTINATION_ADDRESS_3 = 550 | ||
| const DESTINATION_ADDRESS_4 = 551 | ||
|
|
||
| const SCALED_ASSET_AMOUNT_MEM_ADDR = 575 | ||
|
|
||
| # P2ID output note constants | ||
| const P2ID_SCRIPT_ROOT = [13362761878458161062, 15090726097241769395, 444910447169617901, 3558201871398422326] | ||
|
|
@@ -46,6 +69,7 @@ const P2ID_OUTPUT_NOTE_AMOUNT_MEM_PTR = 611 | |
| # ================================================================================================= | ||
|
|
||
| const ERR_INVALID_CLAIM_PROOF = "invalid claim proof" | ||
| const ERR_ORIGIN_ADDRESSES_MISMATCH = "origin token addresses do not match" | ||
|
|
||
| #! Inputs: [PROOF_DATA_KEY, LEAF_DATA_KEY] | ||
| #! Outputs: [] | ||
|
|
@@ -57,6 +81,10 @@ const ERR_INVALID_CLAIM_PROOF = "invalid claim proof" | |
| #! | ||
| #! Invocation: exec | ||
| proc validate_claim | ||
| # Check origin token address matches storage origin address | ||
| exec.assert_origin_address_eq_storage_address | ||
| # => [PROOF_DATA_KEY, LEAF_DATA_KEY] | ||
|
|
||
| # Get bridge_in::check_claim_proof procedure MAST root | ||
| procref.bridge_in::check_claim_proof | ||
| # => [BRIDGE_PROC_MAST_ROOT] | ||
|
|
@@ -81,11 +109,82 @@ proc validate_claim | |
| # => [] | ||
| end | ||
|
|
||
|
|
||
| #! Verifies that the origin token address from the claim matches the stored origin token address. | ||
| #! | ||
| #! This procedure loads the origin token address from the claim data in memory and compares it | ||
| #! against the origin token address stored in the faucet's metadata storage slots. All 5 u32 | ||
| #! limbs of the address must match exactly. | ||
| #! | ||
| #! Inputs: [] | ||
| #! Outputs: [] | ||
| #! | ||
| #! Panics if: | ||
| #! - any of the 5 u32 limbs of the origin token address do not match. | ||
| #! | ||
| #! Invocation: exec | ||
| proc assert_origin_address_eq_storage_address | ||
| mem_load.ORIGIN_TOKEN_ADDRESS_0 | ||
| mem_load.ORIGIN_TOKEN_ADDRESS_1 | ||
| mem_load.ORIGIN_TOKEN_ADDRESS_2 | ||
| mem_load.ORIGIN_TOKEN_ADDRESS_3 | ||
| mem_load.ORIGIN_TOKEN_ADDRESS_4 | ||
| # => [ORIGIN_TOKEN_ADDRESS_CLAIM[5]] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Relying on memory layout in this way feels a bit fragile to me. I'd try to make this procedure a bit more stateless. One approach is to pass in the memory pointer to where the token address is stored as an input - i.e., something like: This would take a few more cycles, but I don't think that's an issue. |
||
|
|
||
| exec.get_origin_token_address | ||
| # => [ORIGIN_TOKEN_ADDRESS[5], ORIGIN_TOKEN_ADDRESS_CLAIM[5]] | ||
|
|
||
| movup.5 assert_eq.err=ERR_ORIGIN_ADDRESSES_MISMATCH | ||
| movup.4 assert_eq.err=ERR_ORIGIN_ADDRESSES_MISMATCH | ||
| movup.3 assert_eq.err=ERR_ORIGIN_ADDRESSES_MISMATCH | ||
| movup.2 assert_eq.err=ERR_ORIGIN_ADDRESSES_MISMATCH | ||
| assert_eq.err=ERR_ORIGIN_ADDRESSES_MISMATCH | ||
| # => [] | ||
| end | ||
|
|
||
| #! Reads the origin token address from the aggfaucet metadata storage slots. | ||
| #! | ||
| #! Inputs: [] | ||
| #! Outputs: [origin_token_addr[0], origin_token_addr[1], origin_token_addr[2], origin_token_addr[3], origin_token_addr[4]] | ||
| #! | ||
| #! Invocation: exec | ||
| proc get_origin_token_address | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe not for this PR, but I'd make this procedure a part of the public interface. Since public interface procedures need to be invoked via the
Comment on lines
+145
to
+151
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These changes don't seem related to how |
||
| # Get first word: [tok1, tok2, tok3, tok4] | ||
| push.AGGFAUCET_METADATA_SLOT_0[0..2] | ||
| exec.active_account::get_item | ||
| # => [tok1, tok2, tok3, tok4] | ||
|
|
||
| # Get second word: [0, 0, scaling_factor, tok0] | ||
| push.AGGFAUCET_METADATA_SLOT_1[0..2] | ||
| exec.active_account::get_item | ||
| drop drop drop | ||
| # => [tok0, tok1, tok2, tok3, tok4] | ||
| end | ||
|
|
||
| #! Reads the scaling factor from the aggfaucet metadata storage slot. | ||
| #! | ||
| #! Inputs: [] | ||
| #! Outputs: [scaling_factor] | ||
| #! | ||
| #! Invocation: exec | ||
| proc get_scaling_factor | ||
| # Get second word: [tok4, scaling_factor, 0, 0] | ||
| push.AGGFAUCET_METADATA_SLOT_1[0..2] | ||
| exec.active_account::get_item | ||
| # => [ 0, 0, scaling_factor, tok4] | ||
|
|
||
| drop drop swap drop | ||
| # => [scaling_factor] | ||
| end | ||
|
|
||
| # Inputs: [] | ||
| # Outputs: [U256[0], U256[1]] | ||
| proc get_raw_claim_amount | ||
| padw mem_loadw_be.OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_0 | ||
| padw mem_loadw_be.OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_1 | ||
| exec.word::reverse | ||
|
|
||
| padw mem_loadw_be.OUTPUT_NOTE_ASSET_AMOUNT_MEM_ADDR_0 | ||
| exec.word::reverse | ||
| end | ||
|
|
||
| # Inputs: [U256[0], U256[1]] | ||
|
|
@@ -94,12 +193,6 @@ proc scale_down_amount | |
| repeat.7 drop end | ||
| end | ||
|
|
||
| # Inputs: [] | ||
| # Outputs: [prefix, suffix] | ||
| proc get_destination_account_id | ||
| mem_load.543 mem_load.544 | ||
| end | ||
|
|
||
| # Inputs: [PROOF_DATA_KEY, LEAF_DATA_KEY, OUTPUT_NOTE_DATA_KEY] | ||
| # Outputs: [] | ||
| proc batch_pipe_double_words | ||
|
|
@@ -128,6 +221,27 @@ proc batch_pipe_double_words | |
| exec.mem::pipe_double_words_preimage_to_memory drop | ||
| end | ||
|
|
||
| #! Extracts the destination account ID as address[5] from memory. | ||
| #! | ||
| #! This procedure reads the destination address from the leaf data and converts it from | ||
| #! Ethereum address format to AccountId format (prefix, suffix). | ||
| #! | ||
| #! Inputs: [] | ||
| #! Outputs: [prefix, suffix] | ||
| #! | ||
| #! Invocation: exec | ||
| proc get_destination_account_id_data | ||
| mem_load.DESTINATION_ADDRESS_4 | ||
| mem_load.DESTINATION_ADDRESS_3 | ||
| mem_load.DESTINATION_ADDRESS_2 | ||
| mem_load.DESTINATION_ADDRESS_1 | ||
| mem_load.DESTINATION_ADDRESS_0 | ||
| # => [address[5]] | ||
|
|
||
| exec.eth_address::to_account_id | ||
| # => [prefix, suffix] | ||
| end | ||
|
|
||
| #! Builds a P2ID output note for the claim recipient. | ||
| #! | ||
| #! This procedure expects the claim data to be already written to memory via batch_pipe_double_words. | ||
|
|
@@ -149,15 +263,16 @@ proc build_p2id_output_note | |
| push.P2ID_NOTE_NUM_STORAGE_ITEMS | ||
| # => [note_num_storage_items, SERIAL_NUM, SCRIPT_ROOT] | ||
|
|
||
| exec.get_destination_account_id | ||
| # => [account_id_prefix, account_id_suffix, note_num_storage_items, SERIAL_NUM, SCRIPT_ROOT] | ||
|
|
||
| mem_store.0 mem_store.1 | ||
| # => [note_num_storage_items, SERIAL_NUM, SCRIPT_ROOT] | ||
|
|
||
| push.OUTPUT_NOTE_INPUTS_MEM_ADDR | ||
| # => [storage_ptr = 0, note_num_storage_items, SERIAL_NUM, SCRIPT_ROOT] | ||
|
|
||
| exec.get_destination_account_id_data | ||
| # => [prefix, suffix] | ||
|
|
||
| # Write destination account id into memory | ||
| mem_store.1 mem_store.0 | ||
| # => [] | ||
|
|
||
| exec.note::build_recipient | ||
| # => [RECIPIENT] | ||
|
|
||
|
|
@@ -167,11 +282,17 @@ proc build_p2id_output_note | |
| mem_load.OUTPUT_NOTE_TAG_MEM_ADDR | ||
| # => [tag, RECIPIENT] | ||
|
|
||
| mem_load.SCALED_ASSET_AMOUNT_MEM_ADDR | ||
| # => [amount, scale_exp, tag, RECIPIENT] | ||
|
|
||
| exec.get_scaling_factor | ||
| # => [scale_exp, tag, RECIPIENT] | ||
|
|
||
| exec.get_raw_claim_amount | ||
| # => [AMOUNT[1], AMOUNT[0], tag, note_type, RECIPIENT] | ||
| # => [AMOUNT[0], AMOUNT[1], amount, scale_exp, tag, note_type, RECIPIENT] | ||
|
|
||
| # TODO: implement scale down logic; stubbed out for now | ||
| exec.asset_conversion::scale_u256_to_native_amount | ||
| # Check that provided bridge amount is valid conversion from EVM amount | ||
| exec.asset_conversion::verify_u256_to_native_amount_conversion | ||
| # => [amount, tag, note_type, RECIPIENT] | ||
|
|
||
| exec.faucets::distribute | ||
|
|
@@ -208,12 +329,13 @@ end | |
| #! destinationAddress[5], // Destination address (5 felts, address as 5 u32 felts) | ||
| #! amount[8], // Amount of tokens (8 felts, uint256 as 8 u32 felts) | ||
| #! metadata[8], // ABI encoded metadata (8 felts, fixed size) | ||
| #! EMPTY_WORD // padding | ||
| #! ], | ||
| #! OUTPUT_NOTE_DATA_KEY => [ | ||
| #! output_p2id_serial_num[4], // P2ID note serial number (4 felts, Word) | ||
| #! agglayer_faucet_account_id[2], // Agglayer faucet account ID (2 felts, prefix and suffix) | ||
| #! output_note_tag[1], // P2ID output note tag | ||
| #! scaled_bridged_amount[1], // Scaled bridged amount (quotient from amount / 10^scale_exp) | ||
| #! padding[1], // padding (1 felt) | ||
| #! ] | ||
| #! } | ||
| #! | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments on this:
u32value)? I'm assuming here that this would allow us to re-use the native serialization of the AggLayer format.miden::agglayer::faucetas the namespace and then add slot names within that namespace.Overall, for slots, I'd probably have something like this:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah - scratch the first point above. Token address is only 20 bytes, so, we already have
u32representation - and we don't need more than 5 elements for them.