# Testing

TONado Cash's test surface spans four layers: contracts (sandbox), circuits (witness/proof generation), off-chain TS units, and end-to-end testnet. This page explains how each is organized and when to run what.

## Test categories

| Scope                                 | Tool                            | Command                                               |
| ------------------------------------- | ------------------------------- | ----------------------------------------------------- |
| Tolk contracts (sandbox)              | `@ton/sandbox` via `acton test` | `pnpm --filter @tonado/contracts test`                |
| Circuit smoke (witness + proof)       | `tsx` direct run                | `tsx apps/contracts/tests/circuit.spec.ts`            |
| Off-chain TS units                    | vitest                          | `pnpm --filter @tonado/core test`                     |
| Poseidon parity (off-chain ↔ circuit) | `tsx` direct run                | `tsx apps/contracts/scripts/check-poseidon-parity.ts` |
| Live testnet end-to-end               | shell script                    | `pnpm e2e:testnet`                                    |

## Contract sandbox tests

The biggest test surface. \~131 tests across:

* `pool.deposit.test.ts`: deposit happy path, denomination validation, field-range checks, duplicate-commitment rejection, paused state, malformed messages, empty-body bounce behavior.
* `pool.withdraw.test.ts`: withdraw happy path, replay protection, unknown-root rejection, field-range checks, fee bounds, paused state, recipient/relayer binding, bounce-on-action-fail rollback.
* `pool.admin.test.ts`: pause/unpause, recover-stuck, not-owner rejection.
* `pool.capacity.test.ts`: `MAX_LEAVES` cell-growth projection.
* `pool.gas.test.ts`: per-handler gas budgets.

These run in [`@ton/sandbox`](https://github.com/ton-org/sandbox), which is an in-process TVM simulator. No network, no Toncenter, no real blockchain, just deterministic message-passing through actual compiled Tolk bytecode.

Run all contract tests:

```bash
pnpm --filter @tonado/contracts test
```

Run a specific test file:

```bash
cd apps/contracts
acton test --filter pool.withdraw
```

**Must be green** before any deploy. The mainnet deploy script enforces this.

## Circuit smoke test

[`apps/contracts/tests/circuit.spec.ts`](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/tests/circuit.spec.ts) is a manual smoke test:

```bash
tsx apps/contracts/tests/circuit.spec.ts
```

It:

1. Generates a deposit with random `(nullifier, secret)`.
2. Computes the commitment.
3. Builds a fake 4-leaf Merkle tree containing the commitment.
4. Generates a Groth16 proof against the tree.
5. Verifies the proof with `verification_key.json`.

This is a sanity check that the prover + verifying key + circuit artifacts agree end-to-end. Run after any circuit change.

## Off-chain TS unit tests

[`packages/core/src/*.test.ts`](https://github.com/tonadocash/monorepo/tree/main/packages/core/src): \~70 vitest unit tests covering:

* Poseidon parity (off-chain vs. circuit).
* Merkle tree correctness (insertion, root recomputation, paths).
* Note parsing/serialization.
* Address ↔ field-element encoding.
* Deposit derivation (note → commitment + nullifier hash).

```bash
pnpm --filter @tonado/core test
```

These run quickly and are the canonical tests for any SDK change.

## Poseidon parity

[`apps/contracts/scripts/check-poseidon-parity.ts`](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/scripts/check-poseidon-parity.ts) is a separate CI job that asserts the off-chain Poseidon and the compiled circom WASM produce identical outputs on a wide range of inputs. Run it after regenerating any circuit artifact:

```bash
tsx apps/contracts/scripts/check-poseidon-parity.ts
```

If parity fails, **stop**. Proofs will silently mis-verify; no other test would catch it.

## Live testnet end-to-end

[`shell/testnet.sh`](https://github.com/tonadocash/monorepo/blob/main/shell/testnet.sh): full deploy → deposit → wait for landing → withdraw → verify recipient delta cycle against a real testnet pool.

```bash
pnpm e2e:testnet
```

Requires:

* `DEPLOYER_MNEMONIC` and `RELAYER_WALLET_MNEMONIC` set in `.env`.
* Both wallets funded with at least 5 testnet TON.
* `TONCENTER_API_KEY` set.

Slow (\~3–5 minutes), but the only test that exercises the full real-world flow end-to-end. Run before any mainnet deploy.

## CI

CI runs on every PR:

1. `pnpm typecheck`: TS strict mode.
2. `pnpm lint`: eslint + prettier.
3. `pnpm format:tolk:check`: `acton fmt` dry-run.
4. `pnpm --filter @tonado/core test`: vitest.
5. `pnpm --filter @tonado/contracts test`: sandbox.
6. `check-poseidon-parity.ts`.
7. Circuit-shape guard: `pnpm --filter @tonado/contracts run circuit-shape:check` confirms the freshly-compiled circuit's structural shape (constraint count, public/private input counts, protocol, curve) matches the committed snapshot at [apps/contracts/circuits/circuit-shape.json](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/circuits/circuit-shape.json).

The circuit-shape guard catches the case where someone edits a `.circom` file but forgets to re-snapshot. A byte-equality gate on the regenerated `verifier.tolk` isn't possible: snarkjs mixes `crypto.randomBytes(64)` into every contribution regardless of the `-e` entropy flag, so VK constants are fresh on every run. **Don't bypass the shape check**. Silently shipping a verifier that doesn't match the deployed zkey is the kind of bug that doesn't surface until you've already lost user funds.

## What's not tested today

The big known gap: **TS unit tests for the relayer**. The relayer is currently exercised only by `pnpm e2e:testnet` and by manual integration testing. Adding vitest coverage for `TornadoOperations`, `Indexer`, and the REST handlers is on the [Mainnet launch plan](/operations/mainnet-launch-plan.md).


---

# 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/for-developers/testing.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.
