> ## 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.

# Contracts overview

> Every Solidity contract in the system, what it does, and whether it is on the default path.

Source lives in `contracts/src/`. Audit brief: `contracts/AUDIT_BRIEF.md`.

## The pool rails — the default path

### MerchantPool

One per merchant per chain. Immutable and ownerless: no admin, no upgrade, no pause. Constructor arguments include recipient, treasury, partner, and the basis-point splits, so all of them are part of the CREATE2 preimage.

```solidity theme={null}
function deposit(bytes16 paymentId, IERC20 token, uint256 amount) external nonReentrant;
function distribute(IERC20 token) external nonReentrant;
function claim(IERC20 token, address account) external nonReentrant;
```

Events: `Deposited(paymentId, token, payer, amount)`, `Distributed(...)`, `Claimed(token, account, amount)`.

<Info>
  No `receive`, no `fallback`, no token hook. A plain ERC-20 transfer into the pool does not execute pool code; the balance is read at distribute time. This is the single most consequential fact about the contract.
</Info>

`distribute()` carves the 50 bps distributor reward from the **merchant** share at `MerchantPool.sol:203`.

### InvoiceForwarder

Per-invoice, at a CREATE2 address salted on `paymentId`. Init code commits the destination pool.

**Sweep-only.** No `refund()`, no window, no `Refunded` event. Remains callable after the first sweep so late payments are recoverable — an earlier `refunded[token]` latch was removed precisely because it could strand funds.

### MerchantRegistry

Roughly 30 lines. The trust contract. Ownerless and `msg.sender`-scoped, so a merchant attests their own payout recipient and nobody else can.

`effectiveRecipient(address)` is **identity-default** — it returns the merchant themselves when no explicit recipient is set, which means even an unattested merchant verifies correctly.

## TRON variants

`MerchantPoolTron`, `InvoiceForwarderTron`, `RouterFeeTron`, `InvoiceSplitterTron`, `SplitterFactoryTron`, and `Create2FactoryTron`.

`Create2FactoryTron` exists because TRON has no canonical Arachnid factory. The `0x41` derivation prefix is the other TRON-specific difference. See [TRON](/economics/tron).

## Legacy and Phase 2

### RouterFee

Roughly 470 lines. The original atomic per-payment splitter. **No longer the default path** and dropped from all merchant-facing reads, but still deployed.

```solidity theme={null}
pay(...)          // direct ERC-20 via Permit2, no swap, 99/0.75/0.25
payNative(...)    // customer pays ETH, wraps to WETH, exact-output swap, refunds unused
payWithSwap(...)  // customer pays any ERC-20, Permit2 pull, V3 exact-out, split
```

The "merchant never loses a dollar" property is literally the exact-output plus `maxIn` invariant: if liquidity is thin or price slips, the swap reverts and the reentrancy guard unwinds the whole transaction atomically.

<Warning>
  `payWithSwap` encodes `V3_SWAP_EXACT_OUT = 0x09`, which is **V2's opcode**. Known bug, requires a redeploy, Phase 2 only. Do not build on this path.
</Warning>

<Danger>
  Never redeploy `RouterFee` or `MerchantRegistry` at new addresses without a migration plan. Existing attestations and integrations point at the current ones.
</Danger>

### InvoiceSplitter

The per-invoice CREATE2 splitter from the pre-pool design. Superseded by the pool model.

## Design constraints that must not change

| Constraint                                        | Why                                           |
| ------------------------------------------------- | --------------------------------------------- |
| CREATE2 salt `keccak256("cryptocheckout.v1")`     | Pinned forever. A new salt is a new protocol. |
| Byte-identical init code across EVM chains        | Gives one pool address on all seven chains.   |
| `token` is a runtime argument, never an immutable | Keeps the forwarder address token-agnostic.   |
| Forwarder stays re-callable                       | Late payments are expected, not exceptional.  |
| `distribute()` stays permissionless               | The regulatory linchpin.                      |
| Pool stays ownerless and immutable                | The custody claim depends on it.              |

## Rejected architectures

Evaluated in full and rejected. Do not re-propose without reading the reasoning.

| Design                      | Gas     | Why rejected                                                                                                                                                                                                                      |
| --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Constructor-sweep forwarder | 83,686  | **One-shot.** A zero-code contract still has nonce 1, and CREATE2 refuses to deploy over a non-zero nonce. `selfdestruct` as an escape also failed to redeploy under Cancun. Every late payment becomes permanent loss.           |
| Constructor-split forwarder | 131,502 | Same one-shot flaw, plus hundreds of small transfers instead of one consolidated payout, and a blacklisted treasury or partner blocking individual invoices. This is the atomic `RouterFee` shape the pool deliberately replaced. |
| Cloned pool                 | —       | See [Clone decisions](/economics/clone-decisions).                                                                                                                                                                                |

The clone's extra 10,115 gas over constructor-sweep buys perpetual recoverability. That is cheap insurance.

## Toolchain

* solc 0.8.24, Cancun EVM, `via_ir` on, optimizer runs 1,000,000
* OpenZeppelin v5.1.0 and forge-std v1.9.4, pinned via submodules
* Roughly 96 unit and invariant tests plus 25 fork tests that skip without environment configuration
