# Contracts spec

## pool\_native.tolk

### Storage cell

```
uint1   paused
address owner
coins   denomination          (e.g. 1_000_000_000 = 1 TON)
ref     merkle_state          (see below)
ref     nullifiers_dict       HashmapE 256 → uint1
ref     ext_info              (empty for native; jetton master + wallet for jettons)
```

### Merkle state cell

```
uint32  next_index
uint32  current_root_index
ref     filled_subtrees       HashmapE 32 → uint256
ref     roots                 HashmapE 32 → uint256  (ring buffer of 30)
```

### Op codes

| Op           | Direction | Meaning                                           |
| ------------ | --------- | ------------------------------------------------- |
| `0xded05701` | inbound   | `OP_DEPOSIT_NATIVE`                               |
| `0x7362d09c` | inbound   | TEP-74 `transfer_notification` (jetton pool only) |
| `0xded05702` | inbound   | `OP_WITHDRAW`                                     |
| `0xded057f1` | inbound   | `OP_ADMIN_PAUSE` (owner only)                     |
| `0xded057f2` | inbound   | `OP_ADMIN_UNPAUSE` (owner only)                   |
| `0xded057a1` | ext-out   | `OP_LOG_DEPOSIT` log message                      |
| `0xded057a2` | ext-out   | `OP_LOG_WITHDRAW` log message                     |

### `OP_DEPOSIT_NATIVE`

**Body:**

```
uint32  op  = 0xded05701
uint64  query_id
uint256 commitment
```

**Attached TON:** `≥ denomination + gas_budget`.

**Effects:**

1. Reject if paused (`ERR_PAUSED`).
2. Reject if commitment was previously seen (`ERR_DUPLICATE_COMMITMENT`).
3. Reject if `msg_value < denomination` (`ERR_WRONG_DENOMINATION`).
4. Insert commitment into the Merkle tree; emit `OP_LOG_DEPOSIT`.
5. Refund the excess (`msg_value - denomination - refund_fee`) to sender.

### `OP_WITHDRAW`

**Body:**

```
uint32  op  = 0xded05702
uint64  query_id
uint256 root
uint256 nullifier_hash
address recipient
address relayer
coins   fee
coins   refund         (= 0 for native pool)
^ref    proof_cell     (see core/pool.ts :: serialiseGroth16Proof)
```

**Effects:**

1. Reject if paused.
2. Reject if `fee > denomination` (`ERR_FEE_EXCEEDS_DENOM`).
3. Reject if `refund != 0` on the native pool.
4. Reject if root not in history (`ERR_UNKNOWN_ROOT`).
5. Reject if nullifier already spent (`ERR_ALREADY_SPENT`).
6. Verify Groth16 proof against `(root, nullifier_hash, recipient_field, relayer_field, fee, refund)`. Reject on failure (`ERR_PROOF_INVALID`).
7. Mark nullifier spent.
8. Send `denomination - fee` to recipient.
9. Send `fee` to relayer (if > 0).
10. Emit `OP_LOG_WITHDRAW`.

### Get methods

| Method             | Signature   | Returns       |
| ------------------ | ----------- | ------------- |
| `is_spent`         | `(nh: int)` | int (boolean) |
| `get_denomination` | `()`        | int           |
| `get_next_index`   | `()`        | int           |
| `get_current_root` | `()`        | int           |
| `get_root_history` | `()`        | tuple of int  |

## pool\_jetton.tolk

Same shape as `pool_native.tolk` but:

* Deposit is delivered via `OP_JETTON_TRANSFER_NOTIFICATION` (0x7362d09c), not `OP_DEPOSIT_NATIVE`. The forward\_payload carries the commitment + prevRoot + newRoot + leafIndex + mergeProof tuple inside a single ref cell (the pool requires the TEP-74 either-bit == 1).
* The `transfer_notification`'s `sender` MUST equal the pool's own jetton wallet, stored in a `JettonConfig` sub-ref of `PoolStorage` and set once via the `AdminBindJettonWallet` op (0xded057f4) at deploy time. Without this check a malicious user could deploy a fake jetton wallet and forge deposits. See \[CLAUDE.md] safety rail.
* Withdraw sends 1–2 TEP-74 `transfer` ops (0xf8a7ea5) to the pool's jetton wallet (one to recipient, optionally one to relayer for fee) rather than plain TON sends.
* `core.refund > 0` is allowed up to `REFUND_CAP` (0.5 TON) so the recipient's fresh jetton wallet has gas for follow-up actions. Native pool keeps `refund == 0`.
* Storage adds `JettonConfig { jettonMaster, poolJettonWallet }` in a sub-ref (1023-bit budget headroom). Inline layout otherwise mirrors `pool_native.tolk`.
* `refund` may be nonzero; covers recipient gas in TON.

## verifier.tolk

Auto-generated by `npx export-ton-verifier`. Do not edit.

The pool calls `verifier_verify(proof_cell, public_signals_cell)` which returns 1 on success, 0 on failure. Internally it loads the verifying key (baked into the verifier code as constants), runs the pairing check using TVM's `BLS_*` opcodes, and asserts the equation holds.

## merkle\_tree.tolk

Library module. Functions:

* `init_merkle_state(): MerkleState`: initialises an empty tree by hashing ZERO\_VALUE up the 20 levels.
* `insert_leaf(mut state, leaf): (leaf_index, new_root)`: appends `leaf`, updates filled-subtrees, advances `current_root_index`, returns the resulting leaf index and root.
* `is_known_root(state, root): int`: checks if `root` is in the 30-deep history ring.

## Errors

See `apps/contracts/contracts/lib/errors.tolk`. All codes are stable; clients depend on them.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tonadocash.com/protocol-reference/contracts-spec.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
