> ## Documentation Index
> Fetch the complete documentation index at: https://docs.geckovision.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# The Receipt

> Simulate before money moves. What a Receipt asserts, what the binding covers, what it deliberately does NOT, and the two paths to get one.

A **Receipt** is the output of Gecko's simulate engine. It closes a built transaction
into one legible, honest verdict, **before any money moves**.

The loop: intent → derive the full account set → external build → unsigned prelude
assembly → `simulateTransaction` against a node → **Receipt** → a `binding` over the
exact bytes. Only a passing Receipt with an exact binding hands back a transaction. The
signer is never Gecko.

## What a Receipt asserts

* **Would this transaction LAND** against a *snapshot* of on-chain state (`status`:
  `pass` / `fail`), via `simulateTransaction` (`sigVerify:false`,
  `commitment:"processed"`). The money paths (`prepare_purchase`, `prepare_instruction`,
  `plan_swap`) simulate the exact bytes with `replaceRecentBlockhash:false`, so the
  binding covers the blockhash the caller is about to sign over.
* **Why it wouldn't**, as a **categorical `revert_class`**, a stable string vocabulary:
  `slippage`, `custom_program_error:<code>`, `insufficient_funds`, `account_error`,
  `other`. Never a fabricated dollar number.
* **Compute units** consumed (`units_consumed`).
* **Best-effort deltas**: `sol_delta` (post − pre lamports for the first tracked account)
  and `tokens_received` (only when a token account is tracked and decodable, otherwise
  `None`, never guessed).
* A **`network_label`** honesty caveat, present on every Receipt.

## What a Receipt does NOT do

<Warning>
  Read this section before you build a policy on top of a Receipt. These limits are
  deliberate, not gaps we intend to close by loosening the claim.
</Warning>

* It does **not predict price or slippage**, only whether the tx lands against a
  snapshot.
* A fork/RPC result is **NOT mainnet**. The `network_label` says so; a surfpool-fork
  Receipt is never presented as mainnet truth.
* It is **state-specific and it expires**. An exact binding dies with its blockhash,
  about 60 seconds; the prepare result carries the budget as
  `expires.last_valid_block_height` and `expires.blocks_remaining`. A receipt taken
  before the buyer decided is a receipt for bytes nobody will sign. Re-running is free.
* It does **not quote a priority fee**. `SetComputeUnitPrice` defaults to 0 in the
  simulated bundle; landing under mainnet load needs a fee the operator (or builder)
  supplies. The Receipt's `units_consumed` is the honest input for the CU *limit*, not
  the price.
* It **stores nothing**. The Receipt is returned to the caller and persisted nowhere
  (the control-plane invariant). No payload, pubkey, or log line is written.
* It **never signs**. No keypair exists on any Gecko path. The one send path,
  `submit_transaction`, relays signed bytes only after they verify at exact strength
  against this receipt's binding, and refuses without one.

## Two paths to a Receipt

<CardGroup cols={2}>
  <Card title="Path A: Gecko runs it" icon="play">
    Hand a built plan (with `fee_recipient` supplied) to the `simulate` MCP tool on the
    program surface; it builds, simulates, and returns the Receipt. One tool call, no
    glue code. On the hosted orquestra surface, `prepare_purchase` and
    `prepare_instruction` do this against a public mainnet RPC by default.
  </Card>

  <Card title="Path B: self-serve" icon="wrench">
    `plan_buy` returns a `simulate` recipe block: fill `fee_recipient`, POST `build_url`
    to get the tx, then run `simulateTransaction` yourself. You own the loop; Gecko
    supplies the correct account set and the recipe.
  </Card>
</CardGroup>

Either path, `fee_recipient` stays an **honest gap**: Gecko will not guess it; the caller
supplies it.

## The proof

Two live side-by-sides, both on a **surfpool mainnet fork** (a mainnet-backed state
snapshot, **not mainnet**), simulation only, \$0, nothing signed, nothing broadcast,
nothing stored.

| Case | Naive path | Gecko |
| - | - | - |
| Pump.fun `buy` | ❌ reverts, `account_error`, `AccountNotInitialized (3012)` | ✅ passes, 86,669 CU |
| Meteora DLMM `swap` | ❌ reverts, derive-only, no ATAs/wrap/bin-arrays | ✅ wrap → swap → unwrap, 81,964 CU |
| Meteora pool derivation | ❌ stale 3-seed scheme derives the wrong pool, silently | ✅ correct 4-seed derivation, differential-proven |

The Pump.fun run reverts on the buyer's uninitialized ATA. The Gecko bundle passes
because it carries a curve-quoted `max_sol_cost`, the recovered `bonding_curve_v2`, the
buyback fee-recipient remaining accounts, an idempotent-ATA prelude, and a compute
budget. The Meteora run exercises the full native-SOL bundle: both ATAs idempotent, wSOL
wrap, the swap with the three bitmap-selected `bin_array` remaining accounts the IDL
never names, and a `CloseAccount` unwrap, one unsigned simulated transaction.

<Note>
  Compute-unit numbers are **measured per run** against a fork snapshot and can vary
  slightly with on-chain state. The stable claim is the side-by-side verdict: the naive
  path's revert class vs Gecko's pass. The `base_factor` derivation row is a separate
  result and carries no CU number.
</Note>

Both runs are re-runnable from the engine repo (they need `surfpool` on `PATH` and a
mainnet RPC), and their verbatim output is recorded in
[`docs/proofs.md`](https://github.com/GeckoVision/gecko-surf/blob/main/docs/proofs.md).

On mainnet, the same receipt has preceded 50 landed transactions as of 2026-09-01. See
[A real transaction](/mainnet).

## Recording an outcome (opt-in)

A run can append its **categorical** outcome (status, revert family plus public code,
compute units, slot, network category, and a values-free recipe hash; never a pubkey,
amount, or log) to a segregated series. The default is **record nothing**; it takes an
explicit `record_to` opt-in.

```bash theme={null}
gecko drift path/to/simulated.jsonl   # exit 0 = stable, 1 = drift detected
```

That series is the episodic memory behind [Stay correct](/stay-correct).

## The binding

A passing receipt on a money path comes back with two more fields:

```
binding           a hash over the exact message bytes that were simulated
binding_strength  "exact": the hash covers the blockhash the caller will sign over
```

Between handing over bytes and getting a signature back, nothing of Gecko's runs. A
signer will sign a substituted transaction just as cleanly, and a custody backend
protects the key, never the action. So the prepare result's `next_step` orders the work:
sign, then `verify_signed_transaction` (signed bytes against the binding), then submit.
`submit_transaction` runs that check itself, at exact strength, before anything reaches
the wire, and refuses without a binding. Verifying after broadcast is a post-mortem;
verifying before it is a decision.

What the binding does not say: that this is the purchase the user wanted. It says the
signed bytes are the bytes a passing simulation attested, against the state observed at
that slot, for as long as that blockhash lives.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.