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

# Canopy Protocol Architecture: Contract Roles and Design

The core contract — `OTCVenue` — is a singleton deployed on Robinhood Chain (Chain ID `4663`, Arbitrum Orbit). A companion `ClaimToken` (one per series) is deployed lazily by the venue on first deferred fill.

## Trade Types

**Spot trades** (`unlockTime == 0`) execute as atomic swaps at fill time. When a buyer calls `fill` on an active spot offer, the contract simultaneously transfers the agreed asset amount from escrow to the buyer and routes the quote token payment directly to the seller. No claim tokens are issued, and no unlock time check is required. The entire exchange settles in a single transaction.

**Deferred (forward) trades** (`unlockTime > 0`) use an escrow-and-claim model. The seller deposits collateral upfront; when a buyer fills the offer, the contract mints ERC-20 claim tokens to the buyer rather than immediately releasing the collateral. Quote token payment flows directly to the seller at fill time — the protocol never custodies quote tokens. After the `unlockTime` timestamp passes, any claim token holder can call the `redeem` function to burn their tokens and receive the underlying collateral on a strict 1:1 basis. This design lets buyers trade their future claim freely as a standard ERC-20 in the interim.

## Series Model

Every deferred offer belongs to a **series** defined by the pair `(asset, unlockTime)`. When the first deferred offer is filled for a unique pair, the OTCVenue automatically deploys a new ERC-20 `ClaimToken` contract for that series. All subsequent fills for offers sharing the same `(asset, unlockTime)` mint claim tokens from that same contract, creating a single fungible instrument backed by pooled escrow.

Each series maintains a `backing` counter that tracks the total collateral currently backing outstanding claim tokens. Because series are isolated, a liquidity or accounting event in one series can never affect another.

The series identifier (`seriesId`) is derived deterministically:

```solidity theme={null}
bytes32 seriesId = keccak256(abi.encode(asset, unlockTime));
```

<Note>
  The series key is `(asset, unlockTime)` — **not** `(asset, quoteToken, unlockTime)`. This means all deferred offers for the same asset with the same unlock time share a single claim token, regardless of which quote token is used for payment. This is what makes claim tokens fungible across different offers.
</Note>

## Offer Lifecycle

Every offer has an **expiry** timestamp (the deadline after which no fills are accepted) and an optional **unlock time** (zero for spot, non-zero for deferred). Key constraints at creation:

* `expiry` must be in the future (`expiry > block.timestamp`)
* For deferred offers, `unlockTime` must also be in the future and `expiry <= unlockTime`

This means a deferred offer always stops accepting fills before its collateral unlocks for redemption.

## Key Design Invariants

The Canopy protocol is built around invariants that hold for every offer and series at all times:

1. **Collateral-first creation.** Offers can only be created with collateral already deposited in the same transaction. The escrow transfer and offer registration happen atomically — there is no promise-based path.

2. **Series solvency.** For every series, `claimToken.totalSupply() == series.backing`, and the venue's balance of the asset covers all backing and all active offer escrow. This is enforced by delta-measured deposits, which correctly handle fee-on-transfer tokens.

3. **No double spend of escrow.** `assetRemaining` is decremented before any transfer or mint (checks-effects-interactions). Cancel zeroes it before returning collateral.

4. **Quote tokens are never custodied.** When a buyer fills an offer, quote tokens are transferred directly to the seller and fee recipient in the same transaction. The venue holds no quote token balance at any point.

5. **Redemption is permissionless and unpausable.** Once `block.timestamp >= unlockTime`, any address holding claim tokens can redeem them. No whitelist, no operator approval, and no seller action is required. The admin has no power over redemption or escrow.

6. **Decimal-correct pricing.** Quote cost uses cumulative full-precision `mulDiv`, so split fills settle to the same aggregate price as a single fill.

`OTCVenue` inherits `ReentrancyGuard` and `Ownable2Step`. `ClaimToken` restricts `mint` and `burn` to the venue (`onlyVenue`) but is otherwise a standard ERC-20. Integrators can use any EVM library (ethers.js, viem, web3.py).

## Next Steps

<CardGroup cols={2}>
  <Card title="Data Structures" icon="database" href="/protocol/data-structures">
    Explore the Offer and Series structs, field semantics, and on-chain storage layout.
  </Card>

  <Card title="Events Reference" icon="bolt" href="/protocol/events">
    Browse every emitted event with parameter docs for indexers and frontends.
  </Card>

  <Card title="Creating Offers" icon="plus-circle" href="/protocol/creating-offers">
    Step-by-step guide to creating spot and deferred offers.
  </Card>

  <Card title="Security Model" icon="shield-halved" href="/protocol/security-model">
    Understand the trust assumptions, access controls, and invariant proofs.
  </Card>
</CardGroup>
