From 58a431b148ae41c823f7de4c35b174df1ad349c8 Mon Sep 17 00:00:00 2001 From: Mike MacCana Date: Wed, 30 Sep 2026 17:01:04 +0000 Subject: [PATCH] Escrow: describe the degenerate-offer checks the program now makes quicknode/solana-program-examples#169 added them: make_offer() refuses a zero amount on either side with ZeroAmount, and a same-token offer is refused by Anchor's duplicate-writable-account check before the handler runs. Name both and the tests that check them, in place of the paragraph that said a production escrow should add them. Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn --- building-financial-products-in-solana/escrow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/building-financial-products-in-solana/escrow.md b/building-financial-products-in-solana/escrow.md index a4255a66..2d346de3 100644 --- a/building-financial-products-in-solana/escrow.md +++ b/building-financial-products-in-solana/escrow.md @@ -126,7 +126,7 @@ Five things must hold before and after every handler: Each is closed by the constraint structure: associated token account derivation binds each token account to its owner and mint, stored-address checks bind the maker and mints to the offer's stored data, and seeds plus bump bind the offer to the program. The *Adversary* chapter shows what happens to programs that skip these checks. - **Unauthorized cancel.** `cancel_offer()` requires the maker's signature and checks it against the offer's stored maker. - **The abandoned offer.** The failure mode that is a missing feature: without `cancel_offer()`, an untaken offer strands the maker's tokens permanently. Every state needs an exit. -- **Degenerate offers.** The account constraints do the structural validation, and structure is most of an escrow. Two handler-level checks belong in any escrow headed to production: reject amounts of zero, and reject offers where the two mints are the same. A swap of a token for a different amount of itself means someone is about to be cheated. +- **Degenerate offers.** An offer with zero tokens on one side, or of a token for a different amount of itself, means someone is about to be cheated. `make_offer()` refuses an offer of zero tokens on either side with `ZeroAmount` (`test_make_offer_rejects_zero_offered_amount` and `test_make_offer_rejects_zero_wanted_amount`). An offer of a token for itself never reaches the handler: with one mint, the maker's token A and token B accounts are the same account, and Anchor refuses the same writable account twice with `ConstraintDuplicateMutableAccount`, which `test_make_offer_rejects_same_mint` checks. ## Testing Considerations