> For the complete documentation index, see [llms.txt](https://docs.goassay.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.goassay.ai/developers/reference/smart-contracts.md).

# Smart contracts

Look up Assay's escrow, stake and configuration contracts, their roles, events and limits.

Assay's contracts hold customer funds and provider stake on **Robinhood Chain**. They enforce who can spend, collect, refund or penalize those funds. Result checking happens off chain; the contracts enforce the signed payment and penalty instructions they accept.

**Addresses: see the Assay app.** Payments and stake use **USDG**. Read the deployed contracts' current settings before preparing a transaction.

## The contracts

| Contract      | Responsibility                                                                                             | Useful reads                                                                                                                    |
| ------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `AssayEscrow` | Customer deposits, account caps, payment-key permissions, signed payments, payment holds and withdrawals.  | `escrowOf`, `held`, `delegationOf`, `delegatesOf`, `effectiveCapsOf`, `DOMAIN_SEPARATOR`                                        |
| `AssayStake`  | Provider deposits, unstaking, reserved penalties, disputes and penalty execution.                          | `stakeOf`, `bondedOf`, `withdrawableOf`, `slashRecordOf`, `DOMAIN_SEPARATOR`                                                    |
| `AssayConfig` | Shared parameters, pause state, blocked accounts, verifier registry and role assignments. Holds no tokens. | `params`, `owner`, `admin`, `arbiter`, `paused`, `blocked`, `verifierKey`, `canSign`, `slashDelaySeconds`, `collectHoldSeconds` |

All three use upgradeable UUPS proxies. The config owner authorizes upgrades and appoints the admin. Upgrades are a separate power from the day-to-day admin role.

## Main functions and events

### Customer funds and payment keys

A delegate is a payment key your wallet authorizes to sign payments within caps and an expiry. It cannot withdraw funds or change account permissions.

| Function                                                | Who uses it and what it does                                                                                              | Main events                                                  |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `deposit(amount)`, `depositFor(...)`                    | A funder transfers approved tokens into their own or another customer's escrow.                                           | `Deposited`                                                  |
| `setLimits(maxVoucherAmount, maxPerWindow)`             | The customer sets account ceilings. Zero caps refuse payments.                                                            | `EscrowLimitsSet`, `CapsHeld` when prior caps are retained   |
| `setLimitsBySig(...)`                                   | Anyone may relay the customer's signed ceiling change.                                                                    | Same as `setLimits`                                          |
| `authorizeDelegate(...)`, `authorizeDelegateBySig(...)` | The customer grants or updates a key; anyone may relay the signed form.                                                   | `DelegateAuthorized`, `DelegateUpdated`, possibly `CapsHeld` |
| `revokeDelegate(delegate)`, `revokeDelegateBySig(...)`  | The customer revokes a key directly or through a signed message anyone may relay. Prior authority has a tightening delay. | `DelegateRevoked`, `CapsHeld`                                |
| `requestWithdraw(amount)`, `requestWithdrawBySig(...)`  | The customer starts the withdrawal wait, directly or through a signed message anyone may relay.                           | `WithdrawRequested` with `availableAt`                       |
| `withdraw()`                                            | The customer claims a matured withdrawal to their own wallet, up to the remaining balance.                                | `EscrowWithdrawn`                                            |

### Payments held for collection

The Solidity payment instruction is named `Voucher`. It binds payer, provider, amount, resource hash, request hash, sequence and issue/expiry times. Its EIP-712 domain binds the chain and escrow contract. You normally let `assay-mcp` construct and sign it.

| Function                                                          | Authority and effect                                                                                                                           | Main events                                                                              |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `redeemVoucher(v, sig)`                                           | Redeemer only. Checks the signature, sequence, time window, account and key caps, provider stake and customer balance. Creates a held payment. | `VoucherRedeemed`, `PaymentHeld`, and `DelegateVoucherRedeemed` for a key-signed payment |
| `redeemVoucherBatch(vs, sigs)`                                    | Same checks, applied atomically to a batch.                                                                                                    | Same events per payment                                                                  |
| `collectHeld(payer, seq)`                                         | Redeemer after `collectableAt`; anyone after the additional timeout. Pays the provider share and treasury fee.                                 | `HeldCollected`                                                                          |
| `refundHeld(payer, seq)`                                          | Redeemer only, before the refund cutoff. Restores the whole amount to customer escrow.                                                         | `HeldRefunded`                                                                           |
| `collectHeldBatch(payers, seqs)`, `refundHeldBatch(payers, seqs)` | Atomic batch forms with the same authority and timing rules.                                                                                   | Same events per payment                                                                  |

`VoucherRedeemed` records redemption into a hold. Use `HeldCollected` to establish provider payment and `HeldRefunded` to establish a return to customer escrow. A refund does not replenish the on-chain spending-window counter.

### Provider stake and penalties

A slash is a penalty deducted from provider stake. Proposing one reserves stake; executing it moves money. A signature from a registered verifier is required for a proposal.

| Function                                                    | Authority and effect                                                                                                                   | Main events                    |
| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| `depositStake(amount)`, `depositStakeFor(provider, amount)` | Fund your own or another provider's stake.                                                                                             | `StakeDeposited`               |
| `requestUnstake(amount)`                                    | Provider moves bonded stake into the waiting pool and restarts its unbonding clock.                                                    | `UnstakeRequested`             |
| `withdrawStake(amount)`                                     | Provider claims matured, unreserved stake to their own wallet.                                                                         | `StakeWithdrawn`               |
| `proposeSlash(attestation, sig)`                            | Anyone may submit a valid verifier-signed data-failure attestation. Checks the penalty ceiling and reserves available stake.           | `SlashProposed`                |
| `executeSlash(requestId)`                                   | Anyone after the stored delay, while pending and within the execution window. Rechecks the verifier and applies provider and key caps. | `SlashExecuted`                |
| `disputeSlash(requestId)`                                   | Named provider, once, before `executableAt`. Freezes execution.                                                                        | `SlashDisputed`                |
| `upholdSlash(requestId)`                                    | Arbiter returns a disputed record to pending. Execution still requires its own call.                                                   | `SlashUpheld`                  |
| `cancelSlash(requestId)`                                    | Admin or arbiter releases the reservation.                                                                                             | `SlashCancelled`               |
| `expireSlash(requestId)`                                    | Anyone releases an expired record, an unresolved timed-out dispute, or one whose verifier can no longer sign.                          | `SlashCancelled` with a reason |
| `disputeSlashBatch`, `upholdSlashBatch`, `cancelSlashBatch` | Atomic forms of those actions with the same caller rules.                                                                              | Same events per record         |

For calculation and wallet steps, use [Staking and penalties on chain](/developers/list-your-api-advanced/staking-and-penalties.md) and [Dispute a stake penalty on chain](/developers/list-your-api-advanced/dispute-a-stake-penalty.md).

### Configuration and roles

| Role or function                                       | Power                                                                              | Main events                                     |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------------------------- |
| Owner: `setAdmin`, proxy upgrades                      | Appoint the admin and authorize upgrades.                                          | `AdminSet`, proxy `Upgraded`                    |
| Admin: `updateConfig`                                  | Set treasury, redeemer, fee, stake and penalty parameters, within contract bounds. | `ConfigUpdated`                                 |
| Admin: `setPaused`                                     | Pause or resume guarded actions.                                                   | `PauseToggled`                                  |
| Admin: `registerVerifier`, `revokeVerifier`            | Manage the keys whose penalty attestations are accepted.                           | `VerifierRegistered`, `VerifierRevokedEvent`    |
| Admin: `setArbiter`, `setSlashDelay`, `setCollectHold` | Choose the dispute arbiter and timing for new records.                             | `ArbiterSet`, `SlashDelaySet`, `CollectHoldSet` |
| `setBlocked`                                           | Admin can block or unblock; arbiter can only block.                                | `BlockedSet`                                    |

The admin cannot be a non-revoked verifier. The arbiter cannot be the admin, redeemer or a non-revoked verifier. A verifier signs penalty evidence; the redeemer submits payments and held refunds; the arbiter rules on stake disputes.

## Pause and blocked accounts

Pause stops escrow deposits, cap changes, withdrawal requests and claims, new key grants, payment redemption and collection. Stake deposits, unstaking, withdrawals, penalty proposals and execution also stop. Guarded escrow and stake fund actions check the relevant blocked accounts too.

Key revocation, held refunds, stake disputes, rulings, cancellation and expiry remain available during pause. These actions reduce authority or change a reservation without paying funds out. Pause and blocking do not themselves move money.

## Limits and clocks

These are contract bounds and defaults, not a statement of the deployment's chosen fee or stake requirement. A basis point (bps) is one hundredth of a percentage point.

| Setting                                           | Bound or default                                                                                                                        |
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Collection hold                                   | Default 3,600 seconds; configurable 60–86,400 seconds; frozen per payment.                                                              |
| Public collection and refund cutoff               | `collectableAt` plus 7 days. Refund closes at that instant.                                                                             |
| Customer withdrawal wait                          | 3,600 seconds.                                                                                                                          |
| Tightening delay for lower caps or revocation     | 3,600 seconds; key authority never extends beyond its prior expiry.                                                                     |
| Payment instruction lifetime                      | At most 300 seconds; up to 120 seconds future clock tolerance; redemption grace 1,800 seconds after expiry.                             |
| Sequence                                          | Nonzero, strictly greater than the last redeemed value; maximum jump 1,000,000. Gaps are allowed.                                       |
| Escrow and key caps                               | Both per-call and window caps apply. A window counter drains over 24 hours; it is not a fixed midnight reset or an exact trailing sum.  |
| Key permission                                    | At most 365 days; up to 16 listed keys per payer.                                                                                       |
| Redemption, held-payment and stake-action batches | 1–64 items; matching arrays where required. One bad item reverts the batch.                                                             |
| Platform take rate                                | At most 3,000 bps (30%). Read `params()` for the actual rate.                                                                           |
| Unbonding period                                  | Configurable 11–30 days.                                                                                                                |
| Penalty proposal delay                            | Default 72 hours; configurable 10 minutes–22 days; frozen per record.                                                                   |
| Penalty execution grace                           | 7 days from `executableAt`.                                                                                                             |
| Unresolved stake dispute timeout                  | 30 days from `disputedAt`.                                                                                                              |
| Penalty attestation lifetime                      | At most 7 days.                                                                                                                         |
| Verifier key lifetime                             | At most 365 days.                                                                                                                       |
| Provider penalty cap                              | Configurable, nonzero and at most 5,000 bps (50%) of the at-risk stake basis; execution must also fit the verifier's current daily cap. |

<details>

<summary>Optional: signing and counter details</summary>

The EIP-712 domain name is `Assay Settlement`, version `2`. Escrow and stake have different verifying contracts. Read `DOMAIN_SEPARATOR` from the relevant proxy. Relayed customer permission changes share an authorization nonce and carry a deadline; these are separate from payment sequences.

The on-chain window counter decays linearly with rounding up. It can permit up to twice the nominal window cap across an arbitrary 24-hour interval. The local MCP's rolling spending record is a separate guard. `effectiveCapsOf` includes temporary prior-cap authority; new-call admission must use current permissions and revocation state instead.

</details>

## Errors

| Contract error                                                          | Meaning                                                         | Next action                                               |
| ----------------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------- |
| `ProgramPaused`, `AddressBlocked`                                       | A guarded action is frozen.                                     | Read current config and account state.                    |
| `NotRedeemer`                                                           | The caller cannot submit that payment action.                   | Use the designated redeemer flow.                         |
| `VoucherSeqNotIncreasing`, `VoucherExpired`                             | Payment sequence or clock is no longer acceptable.              | Reconcile the existing call before signing a replacement. |
| `VoucherExceedsPerCallLimit`, `EscrowWindowLimitExceeded`               | Account caps refuse redemption.                                 | Read current and retained caps and spending counters.     |
| `DelegateVoucherExceedsPerCallLimit`, `DelegateWindowLimitExceeded`     | Key caps refuse redemption.                                     | Check the authorized key's caps.                          |
| `ProviderBelowMinimumStake`, `EscrowInsufficient`                       | Stake or balance is too low.                                    | Restore the required stake or customer balance.           |
| `HeldNotYetCollectable`, `HeldRefundWindowClosed`, `HeldPaymentNotHeld` | Timing or held-payment state does not fit the action.           | Read `held(payer, seq)` before retrying.                  |
| `SlashNotYetExecutable`, `DisputeWindowClosed`, `SlashNotPending`       | Penalty timing or state does not fit.                           | Read `slashRecordOf`.                                     |
| `SlashWindowNotDrained`                                                 | The whole reserved penalty does not yet fit its execution caps. | Wait for capacity; do not split the record.               |
| `EmptyBatch`, `BatchTooLarge`, `BatchLengthMismatch`                    | Invalid batch size or array pairing.                            | Fix the batch before resubmitting.                        |

## Go further

* [Settlement and the hold window](/developers/under-the-hood/settlement.md)
* [Security model](/developers/use-tools-advanced/security-model.md)

## Next

* [MCP tools](/developers/reference/mcp-tools.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.goassay.ai/developers/reference/smart-contracts.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
