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

# Smart contract

> Canvas escrow contract on Base mainnet.

## Contract

| Field    | Value                                                                                       |
| -------- | ------------------------------------------------------------------------------------------- |
| Address  | `0xf808b264E13Bf809C8e86afaF4e14c200931101E`                                                |
| Network  | Base mainnet                                                                                |
| Token    | USDC                                                                                        |
| Basescan | [View on Basescan](https://basescan.org/address/0xf808b264E13Bf809C8e86afaF4e14c200931101E) |

## Functions

### `depositCampaign(campaignId, amount)`

Called by the Canvas relayer when an advertiser funds a campaign. Locks USDC into escrow and associates it with the campaign ID.

Caller: Canvas relayer only (enforced by `campaignDepositor` guard).

### `creditDirectDeposit(depositorAddress, amount)`

Records a direct USDC transfer to the contract without a campaign ID. Used for wallet-based deposits outside the standard campaign flow.

### `logCompletion(campaignId, userId)`

Step 1. Fires immediately after the user's final conversation turn, before Kimi scoring. Records the attempt onchain regardless of quality outcome.

Caller: Canvas relayer.

### `releasePayout(campaignId, ownerWallet, ownerAmount, feeWallet, feeAmount)`

Step 2. Fires after Kimi passes a transcript. Releases USDC to the group owner wallet and the Canvas fee wallet in two separate transfers.

Caller: Canvas relayer.

### `withdrawUnallocated(depositorAddress)`

Refunds unspent campaign budget to the original depositor. No lock period — callable at any time.

Caller: Canvas relayer or depositor directly.

### `totalHeld(depositorAddress)`

View. Returns total USDC currently held in escrow for a depositor.

### `getBalance()`

View. Returns the contract's total USDC balance.

## Payout split

The split is calculated in `payout-batch.ts` on the agent server before the contract calls fire. The contract receives pre-calculated amounts.

Two `releasePayout` calls per passing verification:

* **Owner leg:** 90% of bid price → group owner wallet
* **Fee leg:** 10% of bid price → Canvas platform wallet (`0x8ddD5c22c38d9641B23fe197869DA843fD209b49`)

## Security

* The relayer wallet (`0xbD5f911E8621Ec144681d17a8b59DcDd3f9356d9`) is the only address authorized to call state-changing functions
* The `campaignDepositor` guard prevents unauthorized campaign creation
* The contract holds USDC only
* Advertiser funds are refundable at any time via `withdrawUnallocated`

## Onchain audit trail

Every passing verification produces a `releasePayout` transaction on Base. The transaction hash is included in the completion payload delivered to the advertiser, providing a verifiable per-completion record.
