Compliance rules

Compliance rules are the runtime transfer logic for each asset. They live in Passify's database — not in a smart contract — so you can change a rule without redeploying anything.

Why rules live off-chain

When transfer restrictions are baked into a program, changing one means a redeploy: it costs SOL, invalidates integrations, and breaks composability. Passify keeps rules in Postgres and evaluates them at transaction-build time. Token-2022 transfer hooks call back into this logic, so the on-chain asset stays fixed while the policy around it stays editable.

Rule fields

Each token configuration has exactly one rule set:

FieldMeaning
required_schemaThe attestation schema a wallet must hold.
allowed_jurisdictionsList of permitted jurisdictions, e.g. ["US","CA","GB"].
min_investment_usdMinimum amount per mint or transfer.
max_holdersCap on the number of distinct holders.
transfer_lock_untilOptional timestamp before which transfers are blocked.

How rules are evaluated

On every POST /token/mint or POST /token/transfer, Passify checks the rule set in order and refuses the operation on the first failure, returning a specific error:

403 Forbidden
{
  "error": "rule_violation",
  "detail": "min_investment_usd_100",
  "request_id": "a1b2c3d4"
}

Audit trail

Every rule change is recorded in an append-only audit log with the actor, timestamp, and the before and after values. Nothing is edited in place silently — see the manage-rules guide.

Best practices

  • Keep allowed_jurisdictions as the source of truth for geographic policy — do not duplicate it in app code.
  • Use transfer_lock_until for lock-up periods instead of pausing the asset.
  • Review the audit log after every change to confirm intent and ownership.
  • Test a rule change against a known wallet before enabling it for production traffic.

Last updated