testnet
GitHub

PCL ReasonCodes

mechanism compliance

Standardized rejection codes PCL emits when a transaction fails policy evaluation. Wallets and middleware key off these to drive UX.

When PCL rejects a transaction, the rejection reason is exposed as a standardized code, not free-form text. This lets wallets, agent SDKs, and dapp UIs interpret the failure consistently and (where appropriate) chain it into an automatic recovery flow — for example, prompting a user to complete KYC when EasAttestationRequired is returned. The codes are stable identifiers; new codes are added when new policy templates are introduced, but existing codes are not renamed or repurposed.

V1 ReasonCode set

| ReasonCode | Meaning | Triggered when |
| :--- | :--- | :--- |
| InDenylist | Address is on a denylist | Sender or recipient appears in a DENYLIST_POLICY list |
| EasAttestationRequired | Required EAS attestation missing | EAS_POLICY requires a schema the sender does not hold (or attestation is expired/revoked) |
| VolumeAboveMaxLimit | Per-tx amount exceeds max | VOLUME_POLICY max_limit exceeded |
| VolumeBelowMinLimit | Per-tx amount below min | VOLUME_POLICY min_limit not met |
| PeriodicVolumeAboveLimit | Cumulative period limit exceeded | PERIODIC_VOLUME_POLICY or OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY window exhausted |
| Unauthorized | Caller lacks permission | Policy-mutation call from an account that isn't the PolicyAdmin (global) or contract admin (per-contract config) |
| PolicyAlreadyRegistered | Duplicate registration | register called for a contract that already has a policy entry |
| UnknownPolicyType | Template not registered | A UnitPolicy.template_id references an enum value that hasn't been registered on this network |

How wallets / SDKs should consume these

Treat the ReasonCode as the machine-readable layer. Build your UX off the code, not the human-readable string PCL may also return. For example:

  • EasAttestationRequired → trigger your KYC partner's onboarding flow.
  • InDenylist → terminal rejection; show "this address can't transact" without offering a retry.
  • VolumeAboveMaxLimit / VolumeBelowMinLimit → suggest splitting the transfer or adjusting the amount.
  • PeriodicVolumeAboveLimit → show "daily/monthly limit reached; resets at <next window>".
  • Unauthorized / PolicyAlreadyRegistered / UnknownPolicyType → these are admin-tooling errors; surface as raw error in admin UIs, hide from end-user UIs.


MAWS's policy.preflight returns the same ReasonCode shape — agents call it before transfer.send to avoid wasting gas on rejected transactions.

Adding new codes

When a new PolicyTemplate is registered (network upgrade), one or more new ReasonCodes are added alongside it. Code identifiers are coined in CamelCase, descriptive of the failure (e.g. a future JurisdictionMismatch would map to a hypothetical jurisdiction-checking template). Old codes never disappear — even if the template they came from is deprecated, the code stays so historic transaction failures remain interpretable.
Source: maroo
ESC
Type to search