Skip to main content
Defense-in-depth: multiple independently verifiable guarantees, each addressing a distinct class of vulnerability.

Core Design Principles

1

Checks-Effects-Interactions (CEI)

Every state-modifying function in the OTCVenue updates internal state — balances, fill records, offer status — before making any external token transfer calls. assetRemaining is decremented and assetFilled is incremented before any safeTransfer or safeTransferFrom. This strict ordering means that even if an external call triggers a reentrant callback, the contract’s internal state already reflects the outcome of the current operation.
2

Reentrancy Protection

All state-modifying functions carry explicit reentrancy guards via OpenZeppelin’s ReentrancyGuard. This dual-layer defense (CEI + guard) ensures safety even when interacting with ERC-777 tokens or other callback-capable token contracts whose hooks might attempt to call back into the venue mid-execution. The guard causes the transaction to revert immediately rather than proceeding with corrupted state.
3

Full Collateralization

An offer is not visible or fillable until the seller’s assets are fully escrowed in the contract. Canopy does not support speculative or credit-based offers of any kind. Every fillable order represents real, on-chain collateral that has already been transferred and verified. Buyers face no counterparty risk on the asset leg — the tokens they expect to receive are already locked.
4

Cumulative Precision Arithmetic

Fill costs are computed using a cumulative mulDiv approach: quoteCost = mulDiv(newFilledTotal, pricePerUnit, 10^assetDecimals) - previousQuotePaid. This means split fills produce exactly the same aggregate cost as a single fill of the same total size. An attacker cannot craft fill sequences that exploit rounding to extract more assets than they paid for.
5

Measured Escrow Deposits

When a seller deposits collateral, the venue records the actual received balance — the difference in the contract’s token balance before and after the transfer — rather than the nominal amount the seller declared. This protects the protocol against fee-on-transfer tokens and other transfer mechanics that deliver less than the stated amount. The escrow record always reflects what is truly held.
6

Measured Outbound Transfers

Outbound transfers (to buyers at fill time, to sellers at cancellation, and to redeemers) are also measured. The venue verifies that its own balance decreased by exactly the stated amount and that the recipient’s balance increased. If these checks fail — indicating a token with unsupported transfer behavior — the transaction reverts with UnsupportedTransferBehavior().
7

Cumulative Fill Accounting

Partial fills are tracked cumulatively per offer (assetFilled, quotePaid) rather than computed as running deltas. The contract validates that assetUnits <= assetRemaining on every fill. When assetRemaining reaches zero, the offer is deactivated. This prevents double-counting and makes it structurally impossible for aggregate fills to overdraw the escrow.
8

Fee Snapshotting

Each offer captures feeBps and feeRecipient at creation time. This means the fee terms for an offer are immutable once created — an admin changing the venue’s fee rate cannot retroactively affect existing offers.
9

Permissionless and Unpausable Redemption

No single party — including the protocol owner, the original seller, or any other privileged address — can block or gate claim redemptions after the unlock time. The redeem and redeemWithMinimum functions carry the nonReentrant modifier but not the whenEntryOpen modifier. Even when the entry pause is active, redemption remains fully operational.

Series Isolation

Each series in Canopy maintains its own independent backing counter. The backing and claim supply for one series are entirely separate from every other series. A bug, an accounting imbalance, or an unexpected token behavior in one series has no access to and no effect on the collateral held in any other series. This isolation is structural — there are no shared balance pools or cross-series accounting entries — so you can reason about each series as a self-contained unit.

Trust Model Summary

Understanding what Canopy does and does not hold in trust is essential for integrating or auditing the protocol.
PropertyDetail
Quote token custodyThe venue does not custody quote tokens. Quote payments flow directly from buyer to seller (and fee recipient) at fill time.
Fund flowAssets move directly between counterparties at the moment of fill; there is no intermediate holding period for quote tokens.
Escrowed assetsOnly the asset being sold is held in escrow, and only for the duration between offer creation and fill/cancel/redemption.
AdministrationOwner permissions are intentionally limited to fee configuration and entry pause. See Admin Controls for a full breakdown.
Ownership modelThe venue uses OpenZeppelin’s Ownable2Step, requiring a two-step ownership transfer for safety.
Canopy’s security guarantees apply only to the OTCVenue contract itself. The protocol cannot verify that a token contract behaves correctly, that an RPC endpoint is returning accurate data, or that the contract address you are interacting with is the canonical deployment. Always verify contract addresses against official sources before depositing assets or executing fills.