Skip to main content
Version: 0.15 (unstable)

Part 8: Complete Flows

In this final section, we'll bring everything together and walk through the complete deposit and withdrawal flows, verifying that all the components work as a unified banking system.

What You'll Build in This Part​

By the end of this section, you will have:

  • Understood the complete deposit flow from note creation to balance update
  • Understood the complete withdraw flow including P2ID note creation
  • Verified the entire system works with an end-to-end MockChain test
  • Completed the Miden Bank tutorial! πŸŽ‰

Building on Parts 0-7​

You've built all the pieces. Now let's see them work together:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ COMPLETE BANK SYSTEM β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ Components Built: β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ bank-account β”‚ Storage + deposit() + withdraw() β”‚ β”‚
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ β”‚ deposit-note β”‚ Note script β†’ bank_account::deposit() β”‚ β”‚
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ β”‚ withdraw-note β”‚ Note script β†’ bank_account::withdraw() β”‚ β”‚
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ β”‚ init-tx-script β”‚ Transaction script β†’ initialize() β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Storage Layout: β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ initialized (Value) β”‚ Word: [1, 0, 0, 0] when readyβ”‚ β”‚
β”‚ β”‚ balances (StorageMap) β”‚ Map: user_key β†’ [balance, 0, 0, 0]β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Complete Deposit Flow​

Let's trace through exactly what happens when a user deposits tokens:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ DEPOSIT FLOW β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ 1. USER CREATES DEPOSIT NOTE β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Deposit Note β”‚ β”‚
β”‚ β”‚ sender: User β”‚ β”‚
β”‚ β”‚ assets: [1000 tok] β”‚ β”‚
β”‚ β”‚ script: deposit-noteβ”‚ β”‚
β”‚ β”‚ target: Bank β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 2. BANK CONSUMES NOTE (Transaction begins) β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Bank Account β”‚ β”‚
β”‚ β”‚ vault += 1000 tokensβ”‚ ◀── Protocol adds assets to vault β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 3. NOTE SCRIPT EXECUTES β”‚
β”‚ depositor = active_note::get_sender() β†’ User's AccountId β”‚
β”‚ assets = active_note::get_assets() β†’ [1000 tokens] β”‚
β”‚ for asset in assets: β”‚
β”‚ bank_account::deposit(depositor, asset) ◀── Cross-componentβ”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 4. DEPOSIT METHOD RUNS (in bank-account context) β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ require_initialized() βœ“ Passes β”‚ β”‚
β”‚ β”‚ amount <= MAX_DEPOSIT βœ“ 1000 <= 100k β”‚ β”‚
β”‚ β”‚ native_account::add_asset() ← Confirm β”‚ β”‚
β”‚ β”‚ balances[User] += 1000 ← Update β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 5. TRANSACTION COMPLETES β”‚
β”‚ Bank storage: balances[User] = 1000 β”‚
β”‚ Bank vault: +1000 tokens β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Complete Withdraw Flow​

Now let's trace the withdrawal process:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ WITHDRAW FLOW β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ 1. USER CREATES WITHDRAW REQUEST NOTE β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Withdraw Request Note β”‚ β”‚
β”‚ β”‚ sender: User β”‚ β”‚
β”‚ β”‚ inputs: [serial, tag, β”‚ β”‚
β”‚ β”‚ note_type] β”‚ β”‚
β”‚ β”‚ assets: [withdraw amount] β”‚ β”‚
β”‚ β”‚ target: Bank β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 2. BANK CONSUMES REQUEST (Transaction begins) β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Note script executes: β”‚ β”‚
β”‚ β”‚ sender = get_sender() β”‚ β”‚
β”‚ β”‚ storage = get_storage() β”‚ β”‚
β”‚ β”‚ asset = Asset from inputs β”‚ β”‚
β”‚ β”‚ bank_account::withdraw(...) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 3. WITHDRAW METHOD RUNS β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ require_initialized() βœ“ Passes β”‚ β”‚
β”‚ β”‚ current_balance = get_balance(User) β†’ 1000 β”‚ β”‚
β”‚ β”‚ VALIDATE: 1000 >= 400 βœ“ Passes β”‚ β—€ CRITICAL
β”‚ β”‚ balances[User] = 1000 - 400 β†’ 600 β”‚ β”‚
β”‚ β”‚ create_p2id_note(...) β†’ Output note β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 4. P2ID NOTE CREATED (inside create_p2id_note) β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ script_root = storage[10..13] β†’ MAST digest β”‚ β”‚
β”‚ β”‚ recipient = note::build_recipient( β”‚ β”‚
β”‚ β”‚ serial_num, script_root, β”‚ β”‚
β”‚ β”‚ [user.suffix, user.prefix] β”‚ β”‚
β”‚ β”‚ ) β”‚ β”‚
β”‚ β”‚ note_idx = output_note::create(tag, note_type, β”‚ β”‚
β”‚ β”‚ recipient) β”‚ β”‚
β”‚ β”‚ native_account::remove_asset(400 tokens) β”‚ β”‚
β”‚ β”‚ output_note::add_asset(400 tokens, note_idx) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 5. TRANSACTION COMPLETES β”‚
β”‚ Bank storage: balances[User] = 600 β”‚
β”‚ Bank vault: -400 tokens β”‚
β”‚ Output: P2ID note with 400 tokens β†’ User β”‚
β”‚ β”‚ β”‚
β”‚ β–Ό β”‚
β”‚ 6. USER CONSUMES P2ID NOTE (separate transaction) β”‚
β”‚ User's wallet receives 400 tokens β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Try It: Complete End-to-End Test​

The complete flow is exercised by the three integration tests built up over the previous chapters, which together cover the same init β†’ deposit β†’ withdraw story shown in the diagram above:

  • examples/miden-bank/integration/tests/deposit_test.rs β€” introduced in Part 4. Covers the deposit happy path (deposit_test) plus two failure paths: deposit_exceeds_max_should_fail and deposit_without_init_should_fail.
  • examples/miden-bank/integration/tests/init_test.rs β€” introduced in Part 6. Exercises the init transaction script (init_test) and verifies the initialized flag flips from 0 to 1.
  • examples/miden-bank/integration/tests/withdraw_test.rs β€” introduced in Part 7. Runs init + deposit + withdraw end-to-end (withdraw_test) and asserts the P2ID output note is created with the correct payload.

Running all three together from the workspace root is the closest thing to a single end-to-end run:

>_ Terminal
cargo test --package integration --release -- --nocapture --test-threads=1
Expected output
   Compiling integration v0.1.0 (/path/to/miden-bank/integration)
Finished `release` profile [optimized] target(s)
Running tests/deposit_test.rs

running 3 tests
test deposit_test ... ok
test deposit_exceeds_max_should_fail ... ok
test deposit_without_init_should_fail ... ok

test result: ok. 3 passed; 0 failed; 0 ignored

Running tests/init_test.rs

running 1 test
test init_test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored

Running tests/withdraw_test.rs

running 1 test
test withdraw_test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored

Summary: All Components​

Here's the complete picture of what you've built:

ComponentTypePurpose
bank-accountAccount ComponentManages balances and vault
deposit-noteNote ScriptProcesses incoming deposits
withdraw-request-noteNote ScriptRequests withdrawals
init-tx-scriptTransaction ScriptInitializes the bank
Storage SlotTypeContent
initializedStorageValue<Word>Initialization flag
balancesStorageMap<Word, Felt>Depositor balances
APIPurpose
active_note::get_sender()Identify note creator
active_note::get_assets()Get attached assets
active_note::get_storage()Get note parameters
native_account::add_asset()Receive into vault
native_account::remove_asset()Send from vault
output_note::create()Create output note
output_note::add_asset()Attach assets to note

Key Security Patterns​

Remember these critical patterns from this tutorial:

// ❌ DANGEROUS: Silent underflow!
let new_balance = current_balance - withdraw_amount;

// βœ… SAFE: Validate first
assert!(
current_balance.as_canonical_u64() >= withdraw_amount.as_canonical_u64(),
"Insufficient balance"
);
let new_balance = current_balance - withdraw_amount;

Never use <, > on Felt values directly. Always convert to u64 first:

// ❌ BROKEN: Produces incorrect results
if current_balance < withdraw_amount { ... }

// βœ… CORRECT: Use as_canonical_u64()
if current_balance.as_canonical_u64() < withdraw_amount.as_canonical_u64() { ... }

Congratulations! πŸŽ‰β€‹

You've completed the Miden Bank tutorial! You now understand:

  • βœ… Account components with storage (StorageValue<Word> and StorageMap<Word, Felt>)
  • βœ… Constants and constraints for business rules
  • βœ… Asset management with vault operations
  • βœ… Note scripts for processing incoming notes
  • βœ… Cross-component calls via generated bindings
  • βœ… Transaction scripts for owner operations
  • βœ… Output notes for sending assets (P2ID pattern)
  • βœ… Security patterns for safe arithmetic

Continue Learning​

Build More​

Use these patterns to build:

  • Token faucets
  • DEX contracts
  • NFT marketplaces
  • Multi-signature wallets
  • And more!

Explore the complete banking application:

Happy building on Miden! πŸš€