This Solana program is an escrow — it lets a user swap a specific amount of one token for a desired amount of another token.
For example: Alice offers 10 USDC and wants 100 WIF in return.
Without an escrow, users would have to swap tokens manually and trust each other. The escrow program acts as a trusted third party that only releases tokens to both sides when the swap can complete atomically. Neither party can take the other's tokens and run.
Alice and Bob transact directly with each other through the program, so there's no spread or middleman fee taken on the swap.
Run the tests with pnpm test (as configured in Anchor.toml).
Based on Dean Little's Anchor Escrow, with a few changes to make it easier to discuss in class.
One challenge when teaching is avoiding ambiguity — names have to be clear and not confused with anything else.
- Several custom handler functions were replaced by helpers from
@solana-developers/helpersto reduce file size. - Shared token-transfer logic now lives in
instructions/shared.rs. - The upstream project uses a custom file layout. This version uses the 'multiple files' Anchor layout.
- Contexts are separate data structures from the functions that use them. There's no need for OO-style
implpatterns here — no mutable state is stored in the context, and the methods don't mutate it. - The name 'deposit' was overloaded.
depositis both a verb and a noun, which made the code hard to read:- deposit #1 →
token_a_offered_amount - deposit #2 (in
make()) →send_offered_tokens_to_vault - deposit #3 (in
take()) →send_wanted_tokens_to_maker
- deposit #1 →
seedwas renamed toid, because it conflicted with theseedsused for PDA derivation.Escrowwas used for both the program name and the account that records an offer. People kept confusing the offer account with the vault.Escrow(the program) → stillEscrow.Escrow(the offer) →Offer.
receivewas renamed totoken_b_wanted_amount, sincereceiveis a verb and not a good name for an integer.mint_a→token_mint_a(what the maker offered and what the taker wants).mint_b→token_mint_b(what the maker wants and what the taker must offer).makerAtaA→makerTokenAccountAmakerAtaB→makerTokenAccountBtakerAtaA→takerTokenAccountAtakerAtaB→takerTokenAccountB