Skip to content

Consolidate L2 Withdrawal Events into a Single Enriched Event #115

@JoE11-y

Description

@JoE11-y

Description 📹

On L2 we currently emit two logs per withdrawal:

  • BurnEvent { user, amount, nonce, commitment_hash }
  • WithdrawalHashAppended { index, commitment_hash, root_hash }

This forces the sequencer/indexer to correlate two events per withdrawal. We want one enriched event that includes both the business data and the MMR/commitment metadata.

Proposed Actions

Branch: feat/single-withdrawal-event-with-id

1) Modify L2 MMR append function

Change the function that appends a withdrawal commitment (naming may differ; adjust to your module):

// before (example)
fn append_withdrawal_hash(commitment_hash: felt252) { ... }

// after
fn append_withdrawal_hash(commitment_hash: felt252) -> (new_root: felt252, leaf_index: u256, element_count: u256) {
    // append to MMR
    // return post-append metadata
}
  • Return post-append metadata:

    • new_root (mmr.root after append)
    • leaf_index (position of appended leaf; use u256 if needed)
    • element_count (total leaves/elements after append)
  • Remove any emit WithdrawalHashAppended(...) in this code path.

2) Update the withdrawal entrypoint to accept an explicit ID and compute enriched commitment

Extend the L2 withdrawal flow (e.g., burn function) to accept a withdrawal_id: u256 provided by the sequencer:

#[external]
fn burn_xzb_for_unlock(
    amount_usd: u256,                    // normalized units
    user: ContractAddress,
    withdrawal_id: u256,                 // NEW: sequencer-provided
) {
    // ...
}

Commitment hash must include withdrawal_id:

let commitment_hash = keccak256_packed(
    user,
    amount_usd,
    nonce,                // current per-user or global nonce used in claims
    block_timestamp()
);

3) Replace dual events with a single enriched event

Define a Cairo event struct and emit once with all fields.

#[event]
struct WithdrawalEvent {
    #[key] withdrawal_id: u256,   // indexed key
    #[key] user: ContractAddress, // indexed key
    amount_usd: u256,
    nonce: u256,
    leaf_index: u256,             // from append_withdrawal_hash
    commitment_hash: felt252,     // or split u256 if you store as u256
    new_root: felt252,
    element_count: u256
}

In the withdrawal function:

let (new_root, leaf_index, element_count) = append_withdrawal_hash(commitment_hash);

emit WithdrawalEvent {
    withdrawal_id,
    user,
    amount_usd,
    nonce,
    leaf_index,
    commitment_hash,
    new_root,
    element_count
};
  • Remove emit BurnEvent { ... }.
  • Remove emit WithdrawalHashAppended { ... }.

4) Tests & listeners

  • Unit tests

    • Update tests to expect one WithdrawalEvent with the correct field values.
    • Assert leaf_index, new_root, element_count reflect post-append MMR state.
    • Assert commitment_hash equals what the verifier logic uses.

Acceptance Criteria 🧾

  • Only one event (WithdrawalEvent) is emitted per withdrawal.
  • Event contains: withdrawal_id, amount_usd, user, nonce, leaf_index, commitment_hash, new_root, element_count.

📋 Required Guidelines

  • PR only if assigned
  • Complete within 24 hours
  • Include Close #[issue_id] in PR description
  • Ensure build/tests pass and sequencer logic updated before merge

Metadata

Metadata

Assignees

No one assigned

    Labels

    3 Days ETAWithin Three days, send in a PR. Failure to do so will result in a reassignment of your issues.Cairogood first issueGood for newcomers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions