# Testing

What can be checked from this repository today, and how to rerun it. Commands are `npm` scripts run in each service's folder (`trade/`, `gateway/`, `approver/`), after `npm install` there.

## Summary

| Check | What it covers | Needs |
| --- | --- | --- |
| Unit tests | 411 Vitest tests across the trading service, gateway and withdrawal approver, plus 16 `node --test` tests of presales and the receipts checker on presale transactions | Node 22.18 or later |
| Typecheck | Each service compiles | `npm install` in its folder |
| Custody check | Real Privy wallet, policies and approver co-signing, nothing sent to chain | Privy credentials and a running withdrawal approver (`approver/`) |
| Trading path check | Builds, signs and simulates a buy and a sell on mainnet with real policies | Privy and Helius credentials and a running withdrawal approver |
| Receipts checker | A flagged wallet's memos against the chain | An RPC and a wallet with receipts |

Source: trade/package.json, gateway/package.json, approver/package.json, trade/scripts/

## Unit tests

```bash
cd approver && npm test
cd trade && npm test
cd gateway && npm test
```

None of them touch the network: in `trade/`, `test/setup.ts` refuses any request that isn't to loopback; the approver's tests hand its code fake `fetch` functions, and the gateway's make no requests. Tests that need Privy, Jupiter, Helius or Telegram run against local fakes.

- **Withdrawal approver** (`approver/src/*.test.ts`): notices, delays, bindings, every co-signing check, swap and presale checks, the records and the chain watcher. 125 tests.
- **Trading service** (`trade/server/*.test.ts`): withdrawals and key export end to end, the bot, orders and exits, knots, referrals, receipts and the receipts checker, rent refunds, Privy sign-in and re-confirmation, the launch fee rule, Koine-only buys. 289 tests, run with Vitest, plus 16 run with `node --test`: 11 of the presale transaction check and policy rules (`presale.test.ts`), and 5 of the receipts checker on presale transactions (`verify-presale.test.ts`).
- **Gateway** (`gateway/route.test.ts`): routing and the signed internal requests. 12 tests.

On 2026-11-09, all 411 Vitest tests and all 16 `node --test` tests passed.

Most of these are Mast's tests, rebuilt from development transcripts after its repository was lost. Tests whose last version couldn't be rebuilt, or that test code Koine doesn't have, aren't here. The presale tests (`trade/server/presale.test.ts`) are Koine's own: they build presale transactions the way the launchpad does and check that the trading service refuses each way one could differ. On 2026-11-08 all 11 passed.

Source: approver/vitest.config.ts, trade/vitest.config.ts, trade/test/setup.ts, gateway/vitest.config.ts, trade/server/presale.test.ts, trade/server/verify-presale.test.ts

## Typecheck

```bash
cd trade && npm install && npm run typecheck
```

The same works in `gateway/` and `approver/`.

Source: trade/package.json, gateway/package.json, approver/package.json

## Custody check

`npm run custody-check` in `trade/` creates a new empty wallet in the real Privy API, locks it the way every Koine wallet is locked, and asks Privy and the approver to sign withdrawals, swaps and an export. Every transaction is only signed or refused, never sent, and the exported key is checked, never printed. It prints PASS or FAIL per line and exits with the number of failures.

It needs a running withdrawal approver at `APPROVER_URL` (default `http://127.0.0.1:8791`). Run one locally with `npm run dev` in `approver/`, after `npm run setup` in `trade/` has written its keys to `.env.approver`.

Source: trade/scripts/custody-check.ts, trade/server/config.ts (approverUrl), approver/src/server.ts

## Launch fee check

`npm run launchfee-check` in `trade/` needs only `PRIVY_APP_ID` and `PRIVY_APP_SECRET`. It reads the app's sign-in verification keys from Privy, then makes a new empty wallet with the full current swap policy attached directly (no owner, so the policy alone decides), and asks Privy to sign the launch fee to the treasury, one lamport more, one lamport less, and the fee to another address. Nothing is sent. With `LAUNCH_TREASURY` and `LAUNCH_FEE_SOL` unset it uses a random treasury and 0.25 SOL.

Source: trade/scripts/launchfee-check.ts

## Trading path check

```bash
node --env-file=trade/.env trade/scripts/check.ts [mint]
```

Creates a throwaway user and wallet with the real policies, pre-signs a 0.01 SOL buy and a sell through the normal order code, and simulates both on mainnet. The wallet holds no SOL, so a passing simulation shows the transaction is valid up to funds. Creating the wallet binds it at the withdrawal approver, so this also needs a running approver.

Source: trade/scripts/check.ts

## Receipts

```bash
cd trade && npm run receipts:check -- <wallet> [--key <receipts key address>]
```

See [Receipts](https://docs.koine.markets/terminal/receipts#the-checker).

Source: trade/scripts/receipts-check.ts
