Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,16 @@ install-tools: ## Installs development tools required by the Makefile (mdbook, t
cargo install taplo-cli --locked
cargo install cargo-machete --locked
@echo "Development tools installation complete!"

# -- documentation ---------------------------------------------------------------------------------

AGGLAYER_DIAGRAMS_DIR := crates/miden-agglayer/diagrams
EXCALIDRAW_SOURCES := $(wildcard $(AGGLAYER_DIAGRAMS_DIR)/*.excalidraw)
EXCALIDRAW_PNGS := $(EXCALIDRAW_SOURCES:.excalidraw=.png)

.PHONY: agglayer-spec
agglayer-spec: $(EXCALIDRAW_PNGS) ## Exports AggLayer spec diagrams from .excalidraw to .png

$(AGGLAYER_DIAGRAMS_DIR)/%.png: $(AGGLAYER_DIAGRAMS_DIR)/%.excalidraw
@command -v npx >/dev/null 2>&1 || { echo "npx not found. Install Node.js first."; exit 1; }
npx excalidraw-brute-export-cli -i $< --format png -o $@ --scale 2
258 changes: 213 additions & 45 deletions crates/miden-agglayer/SPEC.md

Large diffs are not rendered by default.

98 changes: 49 additions & 49 deletions crates/miden-agglayer/asm/agglayer/bridge/bridge_config.masm
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,42 @@ use miden::protocol::native_account
# =================================================================================================

const ERR_GER_NOT_FOUND = "GER not found in storage"
const ERR_FAUCET_NOT_REGISTERED="faucet is not registered in the bridge's faucet registry"
const ERR_TOKEN_NOT_REGISTERED="token address is not registered in the bridge's token registry"
const ERR_SENDER_NOT_BRIDGE_ADMIN="note sender is not the bridge admin"
const ERR_SENDER_NOT_GER_MANAGER="note sender is not the global exit root manager"
const ERR_FAUCET_NOT_REGISTERED = "faucet is not registered in the bridge's faucet registry"
const ERR_TOKEN_NOT_REGISTERED = "token address is not registered in the bridge's token registry"
const ERR_SENDER_NOT_BRIDGE_ADMIN = "note sender is not the bridge admin"
const ERR_SENDER_NOT_GER_MANAGER = "note sender is not the global exit root manager"

# CONSTANTS
# =================================================================================================

# Storage slots
const BRIDGE_ADMIN_SLOT=word("agglayer::bridge::admin_account_id")
const GER_MANAGER_SLOT=word("agglayer::bridge::ger_manager_account_id")
const GER_MAP_STORAGE_SLOT=word("agglayer::bridge::ger_map")
const FAUCET_REGISTRY_MAP_SLOT=word("agglayer::bridge::faucet_registry_map")
const TOKEN_REGISTRY_MAP_SLOT=word("agglayer::bridge::token_registry_map")
const BRIDGE_ADMIN_SLOT = word("agglayer::bridge::admin_account_id")
const GER_MANAGER_SLOT = word("agglayer::bridge::ger_manager_account_id")
const GER_MAP_STORAGE_SLOT = word("agglayer::bridge::ger_map")
const FAUCET_REGISTRY_MAP_SLOT = word("agglayer::bridge::faucet_registry_map")
const TOKEN_REGISTRY_MAP_SLOT = word("agglayer::bridge::token_registry_map")

# Flags
const GER_KNOWN_FLAG=1
const IS_FAUCET_REGISTERED_FLAG=1
const GER_KNOWN_FLAG = 1
const IS_FAUCET_REGISTERED_FLAG = 1

# Offset in the local memory of the `hash_token_address` procedure
const TOKEN_ADDR_HASH_PTR=0
const TOKEN_ADDR_HASH_PTR = 0

# PUBLIC INTERFACE
# =================================================================================================

#! Updates the Global Exit Root (GER) in the bridge account storage.
#!
#! Computes hash(GER) = poseidon2::merge(GER_LOWER, GER_UPPER) and stores it in a map
#! with value [GER_KNOWN_FLAG, 0, 0, 0] to indicate the GER is known.
#!
#! Panics if the note sender is not the global exit root manager.
#! Computes hash(GER) = poseidon2::merge(GER_LOWER, GER_UPPER) and stores it in a map with value
#! [GER_KNOWN_FLAG, 0, 0, 0] to indicate the GER is known.
#!
#! Inputs: [GER_LOWER[4], GER_UPPER[4], pad(8)]
#! Outputs: [pad(16)]
#!
#! Panics if:
#! - the note sender is not the global exit root manager.
#!
#! Invocation: call
pub proc update_ger
# assert the note sender is the global exit root manager.
Expand All @@ -65,14 +66,15 @@ pub proc update_ger

exec.native_account::set_map_item
# => [OLD_VALUE, pad(12)]

dropw
# => [pad(16)]
end

#! Asserts that the provided GER is valid (exists in storage).
#!
#! Computes hash(GER) = poseidon2::merge(GER_LOWER, GER_UPPER) and looks up the hash in
#! the GER storage map. Panics if the GER has never been stored.
#! Computes hash(GER) = poseidon2::merge(GER_LOWER, GER_UPPER) and looks up the hash in the GER
#! storage map. Panics if the GER has never been stored.
#!
#! Inputs: [GER_ROOT[8]]
#! Outputs: []
Expand All @@ -81,7 +83,7 @@ end
#! - the GER is not found in storage.
#!
#! Invocation: exec
pub proc assert_valid_ger
proc assert_valid_ger
# compute hash(GER)
exec.poseidon2::merge
# => [GER_HASH]
Expand All @@ -104,14 +106,15 @@ end
#!
#! 1. Writes `KEY -> [1, 0, 0, 0]` into the `faucet_registry` map, where
#! `KEY = [0, 0, faucet_id_suffix, faucet_id_prefix]`.
#! 2. Writes `hash(tokenAddress[5]) -> [faucet_id_suffix, faucet_id_prefix, 0, 0]`
#! into the `token_registry` map.
#!
#! Panics if the note sender is not the bridge admin.
#! 2. Writes `hash(tokenAddress[5]) -> [faucet_id_suffix, faucet_id_prefix, 0, 0]` into the
#! `token_registry` map.
#!
#! Inputs: [origin_token_addr(5), faucet_id_suffix, faucet_id_prefix, pad(9)]
#! Outputs: [pad(16)]
#!
#! Panics if:
#! - the note sender is not the bridge admin.
#!
#! Invocation: call
pub proc register_faucet
# assert the note sender is the bridge admin.
Expand All @@ -120,19 +123,24 @@ pub proc register_faucet

# Save faucet ID for later use in token_registry
dup.6 dup.6
# => [faucet_id_suffix, faucet_id_prefix, origin_token_addr(5), faucet_id_suffix, faucet_id_prefix, pad(9)]
# => [faucet_id_suffix, faucet_id_prefix, origin_token_addr(5),
# faucet_id_suffix, faucet_id_prefix, pad(9)]

# --- 1. Register faucet in faucet_registry ---

# set_map_item expects [slot_id(2), KEY, VALUE] and returns [OLD_VALUE].
# Build KEY = [0, 0, suffix, prefix] and VALUE = [IS_FAUCET_REGISTERED_FLAG, 0, 0, 0]
push.0.0.0.IS_FAUCET_REGISTERED_FLAG
# => [IS_FAUCET_REGISTERED_FLAG, 0, 0, 0, faucet_id_suffix, faucet_id_prefix, origin_token_addr(5), faucet_id_suffix, faucet_id_prefix, pad(9)]
# => [IS_FAUCET_REGISTERED_FLAG, 0, 0, 0,
# faucet_id_suffix, faucet_id_prefix, origin_token_addr(5),
# faucet_id_suffix, faucet_id_prefix, pad(9)]

movup.5 movup.5
# => [faucet_id_suffix, faucet_id_prefix, IS_FAUCET_REGISTERED_FLAG, 0, 0, 0, origin_token_addr(5), faucet_id_suffix, faucet_id_prefix, pad(9)]

push.0.0
# => [[0, 0, faucet_id_suffix, faucet_id_prefix], [IS_FAUCET_REGISTERED_FLAG, 0, 0, 0], origin_token_addr(5), faucet_id_suffix, faucet_id_prefix, pad(9)]
movup.5 movup.5 push.0.0
# => [
# [0, 0, faucet_id_suffix, faucet_id_prefix],
# [IS_FAUCET_REGISTERED_FLAG, 0, 0, 0],
# origin_token_addr(5), faucet_id_suffix, faucet_id_prefix, pad(9)
# ]

push.FAUCET_REGISTRY_MAP_SLOT[0..2]
exec.native_account::set_map_item
Expand All @@ -148,10 +156,7 @@ pub proc register_faucet
# => [TOKEN_ADDR_HASH, faucet_id_suffix, faucet_id_prefix, pad(10)]

# Build VALUE = [0, 0, faucet_id_suffix, faucet_id_prefix]
movup.5 movup.5
# => [faucet_id_suffix, faucet_id_prefix, TOKEN_ADDR_HASH, pad(10)]

push.0.0
movup.5 movup.5 push.0.0
# => [0, 0, faucet_id_suffix, faucet_id_prefix, TOKEN_ADDR_HASH, pad(10)]

swapw
Expand All @@ -167,8 +172,7 @@ end

#! Asserts that a faucet is registered in the bridge's faucet registry.
#!
#! Looks up the faucet ID in the faucet registry map and asserts the registration
#! flag is set.
#! Looks up the faucet ID in the faucet registry map and asserts the registration flag is set.
#!
#! Inputs: [faucet_id_suffix, faucet_id_prefix]
#! Outputs: []
Expand All @@ -177,7 +181,7 @@ end
#! - the faucet is not registered in the faucet registry.
#!
#! Invocation: exec
pub proc assert_faucet_registered
proc assert_faucet_registered
# Build KEY = [0, 0, faucet_id_suffix, faucet_id_prefix]
push.0.0
# => [0, 0, faucet_id_suffix, faucet_id_prefix]
Expand All @@ -202,7 +206,7 @@ end
#! - the token address is not registered in the token registry.
#!
#! Invocation: exec
pub proc lookup_faucet_by_token_address
proc lookup_faucet_by_token_address
# Hash the token address
exec.hash_token_address
# => [TOKEN_ADDR_HASH]
Expand All @@ -213,7 +217,7 @@ pub proc lookup_faucet_by_token_address

# Assert the token is registered: faucet_id_prefix is always non-zero for valid account IDs.
dup.3 dup.3 push.0.0
# => [0, 0, faucet_id_suffix, faucet_id_prefix, 0, 0, faucet_id_suffix, faucet_id_prefix]
# => [0, 0, faucet_id_suffix, faucet_id_prefix, 0, 0, faucet_id_suffix, faucet_id_prefix]

exec.account_id::is_equal
# => [is_id_zero, 0, 0, faucet_id_suffix, faucet_id_prefix]
Expand Down Expand Up @@ -250,8 +254,8 @@ end

#! Asserts that the note sender matches the bridge admin stored in account storage.
#!
#! Reads the bridge admin account ID from BRIDGE_ADMIN_SLOT and compares it against
#! the sender of the currently executing note. Panics if they do not match.
#! Reads the bridge admin account ID from BRIDGE_ADMIN_SLOT and compares it against the sender of
#! the currently executing note.
#!
#! Inputs: [pad(16)]
#! Outputs: [pad(16)]
Expand All @@ -260,9 +264,7 @@ end
#! - the note sender does not match the bridge admin account ID.
#!
#! Invocation: exec
pub proc assert_sender_is_bridge_admin
# => [pad(16)]

proc assert_sender_is_bridge_admin
push.BRIDGE_ADMIN_SLOT[0..2]
exec.active_account::get_item
# => [0, 0, admin_suffix, admin_prefix, pad(16)]
Expand All @@ -280,8 +282,8 @@ end

#! Asserts that the note sender matches the global exit root manager stored in account storage.
#!
#! Reads the GER manager account ID from GER_MANAGER_SLOT and compares it against
#! the sender of the currently executing note. Panics if they do not match.
#! Reads the GER manager account ID from GER_MANAGER_SLOT and compares it against the sender of the
#! currently executing note.
#!
#! Inputs: [pad(16)]
#! Outputs: [pad(16)]
Expand All @@ -290,9 +292,7 @@ end
#! - the note sender does not match the GER manager account ID.
#!
#! Invocation: exec
pub proc assert_sender_is_ger_manager
# => [pad(16)]

proc assert_sender_is_ger_manager
push.GER_MANAGER_SLOT[0..2]
exec.active_account::get_item
# => [0, 0, mgr_suffix, mgr_prefix, pad(16)]
Expand Down
Loading
Loading