Think in receipts · Advanced
Async & cross-contract patterns
On the EVM a transaction is one synchronous, atomic call stack. On NEAR it is a tree of receipts: each one runs on its own shard, commits on its own, and talks to the others only through promises and data receipts that arrive blocks later. Most surprising NEAR bugs, from lost refunds to double spends, come from code written as if the old model still applied.
This module builds the asynchronous model from the ground up. It starts with how a transaction turns into receipts and what a Promise really is, then works through callbacks, joins, batches and gas budgets for whole call trees. The later lessons turn that into designs that survive failure: pending states, idempotent callbacks, compensating actions, and the ordering guarantees you can and cannot rely on.
It finishes with yield/resume (NEP-519), which lets a contract pause until an off-chain worker answers, and with sandbox tests that make every failure branch run before mainnet does. All code is near-sdk 5.x Rust; where Solidity has an analog it is shown alongside.
10 lessons~125 min30 quiz questionsFree · no sign-up
What you’ll learn
- Trace a transaction through its receipts, blocks, outcomes and refunds
- Choose between returning, detaching and chaining a
Promise, and know what the caller sees - Read callback results safely with
#[callback_result]and boundedpromise_result_checked - Fan out with
Promise::andand handle partial failure without paying twice - Use atomic batch actions where they fit and chains where they must
- Budget gas for a whole call tree and always reserve enough for the rollback path
- Model async operations as state machines with ids, pending states and recovery paths
- Build request/response flows with yield/resume and test every branch in a sandbox
Lessons
1. The model
- Transactions, receipts and blocksHow a NEAR transaction becomes receipts: action vs data receipts, which block each one runs in, execution outcomes, and how gas is prepaid, burnt and refunded.
- Anatomy of a PromiseWhat a NEAR Promise really is: a receipt under construction. Low-level Promise::new actions vs #[ext_contract] calls, and what returning a Promise does.
2. Building blocks
- Callbacks in depthNEAR callbacks in depth: #[callback_result] vs #[callback_unwrap], promise_results_count, passing context through, PromiseOrValue, and what the caller sees.
- Joins and fan-outCall several NEAR contracts in parallel with Promise::and, read every result in one callback, and handle partial failure without losing funds or state.
- Batch actions vs chained callsSeveral actions on one NEAR Promise form one atomic receipt; chained .then calls are separate receipts. Build a sub-account factory that refunds on failure.
- Gas budgeting for call graphsBudget gas across a whole NEAR call tree: prepaid vs used gas, static gas and weights per hop, nested callees, callback reserves and the 1 PGas cap.
3. Patterns
- Rollback-safe designs: pending states and sagasDesign NEAR cross-contract flows that survive failure: per-operation ids, pending states, idempotent callbacks, compensating actions and a recovery path.
- Ordering and timing guaranteesWhat NEAR does and does not order: actions, chains, joins, cross-shard and delayed receipts, refunds and block times, and why “next block” is a bad bet.
4. Advanced
- Yield & resume (NEP-519)Pause a NEAR receipt until an off-chain worker answers: Promise::new_yield, YieldId::resume, the 200-block timeout, and building a safe request/response oracle.
- Testing async flowsTest NEAR cross-contract flows in a near-workspaces sandbox: a failing mock callee, gas starvation, per-receipt outcomes and logs, and yield timeouts.