✳ SOLANA ACADEMYCourse overview

Intermediate · LESSON 06 OF 06

6. Builder capstone: design and test a token escrow

By the end, you can design and test a client-to-program escrow workflow with explicit account, authority, and recovery rules.

An escrow moves from awaiting deposit to funded, then to beneficiary release, time-gated refund, or cancellation under defined conditions.
6. Builder capstone: design and test a token escrow workflow. An escrow moves from awaiting deposit to funded, then to beneficiary release, time-gated refund, or cancellation under defined conditions.
The maker creates an escrow, then deposits the agreed SPL token amount. The beneficiary may release it. If the deadline passes first, the maker may refund it. The maker can cancel an empty escrow. After a terminal state, surplus is recovered and an empty vault and escrow state can be closed.
Token escrow lifecycle and terminal cleanup. The maker creates an escrow, then deposits the agreed SPL token amount. The beneficiary may release it. If the deadline passes first, the maker may refund it. The maker can cancel an empty escrow. After a terminal state, surplus is recovered and an empty vault and escrow state can be closed.
The maker signs creation and deposit and supplies rent and transaction fees. A maker counter PDA preserves the next unique escrow ID. The escrow state PDA stores parties, mint, amount, refund time, and status. A vault token-account PDA is owned by the SPL Token Program and controlled by a separate vault-authority PDA. The program signs for the vault authority only through a constrained cross-program invocation. Release sends to the beneficiary's token account; refund and surplus recovery return tokens to the maker's token account.
Token escrow account and authority map. The maker signs creation and deposit and supplies rent and transaction fees. A maker counter PDA preserves the next unique escrow ID. The escrow state PDA stores parties, mint, amount, refund time, and status. A vault token-account PDA is owned by the SPL Token Program and controlled by a separate vault-authority PDA. The program signs for the vault authority only through a constrained cross-program invocation. Release sends to the beneficiary's token account; refund and surplus recovery return tokens to the maker's token account.

Read the workflow

The maker creates an escrow with explicit terms and deposits the exact token amount into a PDA-controlled vault. The beneficiary can claim once; the maker may refund only after the deadline, or cancel before funding under the defined rules. Terminal vaults are safely closed after recovery. The maker’s monotonic sequence prevents reuse after escrow cleanup.

  1. AWAITING DEPOSIT
  2. FUNDED
  3. RELEASED
  4. REFUNDED
  5. CANCELLED

FIELD NOTE 01

Choose narrow escrow rules

Build a small escrow for one asset and one agreed condition. Specify who can create it, who deposits, who receives on release, and what happens on refund or expiry. State the invariants before writing instructions: only the recorded mint enters the vault, only the authorized party can release it, and the same deposit cannot be released twice. The teaching lab uses a fixed legacy SPL Token Program, but lets the maker choose a mint and does not assess that mint’s issuer, freeze, or other authority policy. Use synthetic lab tokens; a real application must define its accepted-mint and authority policy before taking deposits. Use synthetic test accounts in LiteSVM or an isolated local validator. Avoid arbitrary token support or Mainnet deployment in the first version.

FIELD NOTE 02

Assess accepted-mint policy

The capstone uses synthetic classic SPL tokens and a maker-selected mint to test escrow mechanics; it does not certify a real token or issuer. Before a real application accepts deposits, define an explicit mint allow-list and inspect the mint account’s program, mint authority, freeze authority, and enabled Token-2022 extensions. A live mint authority may issue more supply, and a live freeze authority may freeze token accounts. Record which controls the application accepts and reject unsupported configurations before funds enter escrow.

FIELD NOTE 03

Map escrow and token accounts

Draw the escrow state account, PDA authority, token mint, vault token account, depositor token account, beneficiary account, program ID, and fee payer. Record which program owns each account and which signer controls each transition. Derive the escrow state and vault authority from documented seeds, and verify canonical addresses in every instruction. For token movement, validate the mint, token program, source, destination, and authority together; a valid address in isolation does not establish the intended relationship.

FIELD NOTE 04

Specify create, deposit, release, and refund

Define the state machine and exact account changes for every instruction. Creation records the parties, mint, amount limit, and release condition. Deposit moves the correct tokens into the vault and records the deposit once. Release transfers only to the agreed beneficiary; refund follows its own authorization and timing rule. Close is permitted only when the escrow reaches a terminal state and protected balances are zero. Check arithmetic bounds and reject stale, duplicate, or out-of-order operations.

FIELD NOTE 05

Build a client that handles real transaction states

The client obtains a recent blockhash, constructs the expected instructions, simulates when appropriate, and displays the asset, amount, destination, and fee payer before asking the wallet to sign. Preserve the signature and blockhash lifetime after submission. A rejected prompt is cancellation; an RPC timeout is uncertainty; a confirmed or finalized status is a network observation. On refresh, recover the same escrow and signature before offering a retry. Do not automatically submit a second deposit because the first response was lost.

FIELD NOTE 06

Protect the program boundary

Treat account addresses and instruction data as untrusted. Verify the escrow PDA, state owner, mint, vault authority, token account owner, beneficiary, signer, and state transition. If a token CPI is used, pass only the required accounts and target the expected token program. Prevent a caller from substituting a mint or destination while keeping the same escrow state. Define errors that explain the rejected precondition without leaking private account data.

FIELD NOTE 07

Test negative cases and recovery

Run the compiled SBF program in LiteSVM for the normal flow and for a wrong signer, wrong mint, substituted vault, wrong beneficiary, duplicate deposit, duplicate release, early refund, and unsolicited vault transfers. For rejected program calls, assert both the error and unchanged protected balances and state. A submitted on-chain transaction can still charge its fee payer when execution fails, so report network fees separately from protected escrow state; local harness cost is not a live fee quote. For client failures, separately mock delayed, null, and stale responses. A mocked RPC test does not prove program enforcement, and a local SBF test does not prove a deployed program has the same bytes or authorities.

FIELD NOTE 08

Package evidence and disclose limits

Deliver the source revision, account map, instruction table, threat model, test commands, client-state diagram, and recovery instructions. A reviewer should reproduce the project from a clean checkout using local test assets. Label Devnet or Mainnet observations separately from local execution. The course exam measures the published assessment; this capstone exercise is not independently reviewed unless a separate reviewer evaluates the actual artifact against a published rubric. Do not describe it as a security audit or production-ready financial software.

FIELD NOTE 09

Token-2022 hooks change the transfer workflow

The included escrow lab intentionally uses the classic SPL Token Program; its passing tests do not establish Token-2022 compatibility. A Token-2022 mint may configure a Transfer Hook, which runs its hook program on every transfer through a cross-program invocation. The transaction must include the extra accounts listed by the hook’s on-chain ExtraAccountMetaList. A transfer that omits or supplies stale hook accounts fails onchain; the hook is not silently skipped. Before signing, a compatible client resolves the current hook and extra accounts for that transfer and simulates the complete transaction. The hook program and its required accounts can change, so do not reuse a stale resolution. Until the escrow and client test that full path, restrict accepted mints explicitly.

MAKE THE CONNECTION

A detail worth keeping

Trace a deposit through the wallet, client message, fee payer, escrow program, token CPI, vault account, and stored state. Then substitute one account at a time and show which program invariant rejects the attempt. For a hook-enabled token, trace how the client detects the extension, resolves its ExtraAccountMetaList accounts, simulates, and preserves those accounts in the exact transaction the wallet approves.

Work through an example

Simulate an RPC timeout after the deposit transaction is submitted. Reconcile the original signature and vault state before retrying. Prove that a repeated request cannot increase the deposit twice or release funds to a substituted beneficiary.

Produce a token escrow package containing a state diagram, canonical PDA seeds, account constraints, client signing flow, five adversarial test cases, and a recovery report for a lost submission response.

GUIDED PRACTICE · INTERMEDIATE

Do the work, one step at a time

Use fictional addresses and disposable test data. Do not enter a recovery phrase or private key. Unless a lesson explicitly says “read-only Devnet,” use paper or a local test and do not connect to a public network.

  1. Write escrow invariants and draw the state, token accounts, signers, PDA authority, and fee payer.
  2. Specify create, deposit, release, refund, surplus recovery, cancellation, and close transitions with exact account constraints.
  3. Build and run the fixed-mint escrow as SBF in the included local LiteSVM suite with synthetic accounts and the SPL Token Program.
  4. Test wrong signer, wrong mint, substituted vault, wrong token destination, duplicate release, early refund, surplus recovery, and close invariants; document which client recovery cases still need RPC mocks.
  5. Package reproducible evidence and mark which claims remain unproven without Devnet or an independent reviewer.
  6. Write a supported-mint matrix for legacy SPL Token, Token-2022 without a hook, and hook-enabled Token-2022. Mark which cases the included fixed-token lab actually executes; specify an explicit reject or support decision for each other case without claiming unrun behavior.

Before you move on, check your reasoning

  • Document accounts, authorities, and allowed state transitions.
  • Implement or specify one complete escrow lifecycle with local tests.
  • Present adversarial results and recovery evidence.

OPEN SELF-CHECK · UNGRADED

Pause and test your reasoning

A transfer-hook mint requires extra accounts, but a client submits a transfer without them. What should the application expect?

  1. The hook is skipped automatically because token transfers are atomic.
  2. The transfer can fail; the client should resolve the required accounts for that transfer and simulate the complete instruction set.
  3. The token account owner can bypass the hook by changing the transaction label.
Reveal one best answer and its explanation

One best answer: The transfer can fail; the client should resolve the required accounts for that transfer and simulate the complete instruction set.

A configured transfer hook participates in the token transfer and may require additional accounts. Resolve the hook’s current account list and simulate the exact transfer before asking a wallet to sign; missing or stale accounts are not silently ignored.

Sources: Transfer Hook Integration Guide ↗ · Transactions ↗

This practice is not scored, saved, or part of a certificate. Account-based lesson checkpoints and level exams remain separate.

Scored checkpoints and level exams are online and require a free account. They are not included in this pack.

Optional lab files

These files are included with the pack. Follow the safety and toolchain notes in the lesson before running a lab; a Devnet read requires an internet connection.

READ THE SOURCE

Go deeper in the official docs

Reviewed on 2026-09-29. Protocol documentation can change; check the linked page’s current version when you reconnect.