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

# Contract conventions

> Foundry setup, deployment rules, and the constraints that must survive every change.

## Toolchain

| Setting          | Value                    |
| ---------------- | ------------------------ |
| solc             | 0.8.24                   |
| EVM version      | Cancun                   |
| `via_ir`         | on                       |
| `optimizer_runs` | 1,000,000                |
| OpenZeppelin     | v5.1.0, submodule-pinned |
| forge-std        | v1.9.4, submodule-pinned |

Per-chain configuration lives in `contracts/config/chains.json`. The deploy script is `contracts/script/Deploy.s.sol`.

## Deployment rules

<Warning>
  `vm.startBroadcast` deploys through the **canonical CREATE2 factory** at `0x4e59b44847b379578588920cA78FbF26c0B4956C`, inherited from forge-std, **not** through the EOA. Predict addresses using the factory, never `vm.addr(key)`.
</Warning>

* The salt is `keccak256("cryptocheckout.v1")`, pinned permanently.
* Init code must be byte-identical across EVM chains so a merchant's pool address is the same everywhere.
* TRON uses `Create2FactoryTron` and the `0x41` prefix.

<Danger>
  **Mainnet deploys require explicit human GO, per chain.** This is guardrail number one. No agent or automation may broadcast to a mainnet.
</Danger>

## Foundry gotchas

These have each cost real time.

* `vm.parseJsonAddress` reverts on `null`, and cheatcode reverts are **not** try/catchable. Use `vm.keyExistsJson` plus a length check instead.
* Foundry 1.5+ treats `address(this)` inside a `Script` contract as a fatal error.
* `Deploy.t.sol` writes test fixtures into `contracts/deployments.json` and `contracts/deployments/`. The per-chain directory is gitignored; the merged top-level file is **not**.

<Danger>
  Always run `git checkout -- contracts/deployments.json` after `forge test`. A polluted copy breaks `_shared/contracts.ts` and the `/verify` page at runtime. CI fails if it is dirty.
</Danger>

## Invariants to preserve

Any change must keep all of these true.

<AccordionGroup>
  <Accordion title="The pool is immutable and ownerless">
    No admin, no upgrade path, no pause. The custody claim depends on it entirely.
  </Accordion>

  <Accordion title="distribute() is permissionless">
    Named the regulatory linchpin. Any gate on it — including a debt check — converts a bounded fee into a withholding power and undoes the non-custody position.
  </Accordion>

  <Accordion title="The forwarder stays re-callable">
    Late payments to spent addresses are an expected event, not an edge case. One-shot designs turn them into permanent loss.
  </Accordion>

  <Accordion title="token is a runtime argument">
    Never an immutable. Making it an immutable would make the forwarder address token-specific and break currency-agnostic acceptance.
  </Accordion>

  <Accordion title="Treasury and partner are computed on gross">
    Any fee or reimbursement carved out must come from the merchant share, never off the top, or the partner's 0.25% silently shrinks.
  </Accordion>

  <Accordion title="Init code commits the payout configuration">
    This is what makes client-side re-derivation a real check rather than a formality.
  </Accordion>
</AccordionGroup>

## Testing

```bash theme={null}
cd contracts && forge test          # ~96 unit + invariant, 25 fork (skip without env)
cd contracts && forge build --quiet # silent build for CI
```

Fork tests skip when their environment variables are absent, so a green local run does not mean the fork suite ran.

Any change to address derivation must re-run the full fork and invariant suite **and** verify a real deploy-and-sweep on Base Sepolia before it is considered done.

## Commit discipline

* Red-test commit **before** green-implementation commit, as separate commits, never collapsed.
* Subject patterns: `feat(ws<N>) Phase X: <what>`, `test(ws<N>) Phase X: <what>`, `fix(ws<N>) <FINDING-ID>: <what>`, `docs(...): <what>`.
* Never `--no-verify`. Never amend after a hook failure — investigate the failure.

## Branching

`main` is the single source of truth and the production line. Pushing to `main` auto-deploys production, so **never push directly**. Every change lands via a pull request against `main`; the PR is the deploy gate.

Short-lived branches are `feat/<name>`, `fix/<name>`, or `docs/<name>`, deleted on merge. Use git worktrees for isolation, branching from `main`. There is no integration branch.
