Skip to main contentPASS
Read the docs

Developers

One decision before execution

Integration is a single evaluated check, placed where an action becomes irreversible. It takes what is actually being proposed, evaluates it against the mandate governing the actor, and returns an outcome with a reason. The caller proceeds on one answer and refuses on every other.

01Integration model

A check placed where the action becomes irreversible

The check is called before an execution rather than reconciled after one. It is given the account being acted for, the target, the asset, the action and the amount. The shape does not change between environments; only its position does.

// Evaluated before the action is carried out.
(bool allowed, bytes32 reason) = pass.checkPolicy(
    account,
    target,
    asset,
    action,
    amount
);

if (!allowed) {
    revert PolicyRefused(reason);
}

Both forms are the same interface expressed for two callers. Onchain the decision is returned in reduced form — allowed is true exactly when outcome is AUTHORIZED — and the refusal reverts the execution. Offchain, the refusal stops a call from being submitted at all.

Call inputs

account
The party being acted for. Policy is evaluated against the mandate binding this actor to this subject, not against the key that signed.
target
The contract the call would reach. It determines which adapter, if any, is able to describe what the call does.
asset
The instrument being moved. Asset permissions are an explicit allow set — AAPL and NVDA in the running mandate, nothing outside it.
action
What is being done with the asset. Trading it and bridging it are separate permissions; an actor can hold one without the other.
amount
The size of the movement, in the unit the adapter resolves value to. The per-transaction ceiling and the room left in the period are both evaluated against it.

What the decision means

A decision is a pair. outcome is AUTHORIZED only when every applicable rule was evaluated and satisfied, and BLOCKED otherwise. reason names the first rule that refused, or AUTHORIZED when none did. Because it is an identifier rather than a message, a caller can branch on it and record the value an auditor will later read.

AUTHORIZED is an assertion about policy only. It states that this actor was permitted to do this thing, for this party, under these constraints. It makes no claim about whether the trade is a good one, whether the counterparty settles, or whether the target protocol behaves as documented. Those are real questions, answered elsewhere.

A refusal is not an error to be retried. It is a completed evaluation with a negative result, and the reason tells the caller which of several very different situations it is in.

Decision
interface Decision {
  /** AUTHORIZED only when every applicable rule was evaluated and satisfied. */
  outcome: 'AUTHORIZED' | 'BLOCKED';
  /** The first rule that refused, or AUTHORIZED. */
  reason: ReasonCode;
}

02Placement

How close the check sits to the point of no return

Three positions, one consistent trade. The closer the check sits to the point where state changes, the fewer paths there are around it, and the more of the surrounding system has to accommodate it.

  1. Inside the executing contract

    Covers
    Every call that reaches this contract, from any caller.
    Proximity
    At the point of state change. No path to the action avoids it.
    What it costs
    The contract has to be written to hold the check. One already deployed without it cannot acquire it.
  2. In a guard in front of an account

    Covers
    Every action the account takes, including protocols it has never touched before.
    Proximity
    One hop before settlement. The account cannot act except through the module holding the check.
    What it costs
    The account has to support a guard, and that guard becomes a dependency of everything the account does.
  3. At the agent’s execution boundary

    Covers
    What this agent proposes. Anything else holding the same key is unaffected.
    Proximity
    Before submission — furthest from the point of no return, and the cheapest place to refuse.
    What it costs
    Nothing onchain enforces it. An agent that is bypassed or replaced takes the check with it.

The positions compose rather than compete. A guard is enforcement; an agent-side check is triage. An agent evaluating its own proposal refuses what it can determine cheaply, before anything is broadcast, and the guard refuses what the agent got wrong.

Because both call the same interface and receive the same reason codes, the two layers cannot disagree about why an execution did not proceed. What changes between them is coverage, not verdict.

03Policy evaluation

The order of the checks is part of the specification

Policy is not a set of conditions evaluated in whatever order is convenient. It is a defined sequence. Evaluation stops at the first rule that is not satisfied, and that rule is the reason returned.

The sequence runs from the most fundamental question to the most specific. A mandate that does not exist cannot have a limit; an asset outside the allow set does not need to be priced. Each check is meaningful only once the ones before it have passed.

That is what makes a reason code useful rather than merely descriptive. A caller receiving DAILY_LIMIT_EXCEEDED knows the actor is bound, the mandate is live, the required credential is held, and the asset, action and venue are all permitted. The trade sat within the $2,500 per-transaction ceiling; the $10,000 of daily exposure is what ran out. That situation has a specific remedy, and it is nothing like ACTION_NOT_ALLOWED.

A decision therefore names one reason and not a list. The same intent evaluated against the same state returns the same reason, which is the property an audit trail can be built on.

  1. 01Actor bindingIs this actor bound to a mandate for this subject?
    • ACTOR_NOT_AUTHORIZED
  2. 02Mandate lifecycleIs that mandate live — inside its window, not suspended?
    • MANDATE_EXPIRED
    • MANDATE_SUSPENDED
  3. 03CredentialsDoes the subject hold every credential the mandate requires?
    • MISSING_CREDENTIAL
    • CREDENTIAL_EXPIRED
    • CREDENTIAL_REVOKED
  4. 04ActionIs this kind of action permitted at all?
    • ACTION_NOT_ALLOWED
  5. 05AssetIs this asset named in the allow set?
    • ASSET_NOT_ALLOWED
  6. 06VenueWas the intent produced by a permitted adapter?
    • ADAPTER_NOT_ALLOWED
  7. 07Transaction limitIs this single movement within its ceiling?
    • TX_LIMIT_EXCEEDED
  8. 08Periodic limitIs there room left in the period for it?
    • DAILY_LIMIT_EXCEEDED
  9. DecisionReturned to the caller, with its reason
    • AUTHORIZEDwhen no rule refused

04Reason codes

Every decision names the rule that produced it

The reason is a stable identifier rather than a message, so callers, logs and audit trails agree on why an execution did or did not proceed. The set is closed; this is all of it, AUTHORIZED included, because the reason field always carries a value.

The complete set of PASS decision reason codes.
CodeCategorySummary
AUTHORIZEDOutcomeEvery applicable rule evaluated successfully.
MISSING_CREDENTIALCredentialA credential required by the mandate is not held by the subject.
CREDENTIAL_EXPIREDCredentialA required credential exists but is past its validity window.
CREDENTIAL_REVOKEDCredentialA required credential was withdrawn by its issuer.
ASSET_NOT_ALLOWEDPermissionThe asset in the execution intent is outside the permitted set.
ACTION_NOT_ALLOWEDPermissionThe action type is not permitted under this mandate.
ADAPTER_NOT_ALLOWEDPermissionThe execution venue is not among the permitted adapters.
TX_LIMIT_EXCEEDEDLimitThe single-transaction ceiling was exceeded.
DAILY_LIMIT_EXCEEDEDLimitThe cumulative exposure limit for the period was exceeded.
MANDATE_EXPIREDLifecycleThe governing mandate is past its validity window.
MANDATE_SUSPENDEDLifecycleThe mandate is temporarily inactive.
ACTOR_NOT_AUTHORIZEDLifecycleThe actor is not bound to a mandate for this subject.
INVALID_EXECUTION_CONTEXTContextThe execution intent could not be validated into policy inputs.

Handling a refusal

The families are not interchangeable. Each points at a different part of the system, and that is what determines the correct response.

CredentialIssuance or renewal
The mandate is intact and the permission unchanged; the subject’s passport does not carry a valid attestation of a required type. The resolution is a new or renewed credential from an issuer, not an edit to the mandate.
PermissionAn amendment by the granting party
The actor proposed something the mandate does not permit. This is a refusal working as specified, not a fault to route around. If the actor should be permitted, the granting party widens the allow set deliberately, and that widening is itself a record.
LimitTime, or a deliberate change to the bound
A periodic limit clears when its window rolls, so waiting is a legitimate response. A per-transaction ceiling does not clear, and splitting an amount to fit beneath it defeats the purpose of setting one — which is what the periodic limit catches.
LifecycleA grant, a reinstatement or a renewal
The mandate is not currently a source of authority: expired, suspended, or never bound to this actor. Each is an operator action rather than an integration change, and suspension preserves the definition, so reinstating it is not reconstructing it.
ContextAdapter coverage for the target
No adapter could derive a trustworthy asset, action, venue and value from the call. The call may be well formed; PASS refuses because it will not evaluate policy against a description it cannot verify itself.

05Adapters

An adapter answers for one protocol, or refuses

Policy needs an asset, an action, a venue and a value. Deriving those four things from a call at a specific target is the whole of an adapter’s job, and it is a job with only two acceptable outcomes.

  1. Raw callBytes proposed by an actor
  2. Protocol adapterDecodes against a known target
  3. Validated intentWhat is actually being proposed
    • Asset
    • Action
    • Value
    • Venue
  4. PASS policyEvaluated against the mandate
  5. ExecutionProceeds only on AUTHORIZED
IExecutionAdapter
interface IExecutionAdapter {
    /// @notice Derives what a proposed call actually does.
    /// @dev MUST revert rather than return an uncertain result.
    function resolve(
        address target,
        bytes calldata data,
        uint256 value
    ) external view returns (ExecutionIntent memory intent);
}

struct ExecutionIntent {
    address asset;
    bytes32 action;
    uint256 value;
    address venue;
}

resolve is a view over a target the adapter is written for. It returns an execution intent — asset, action, value, venue — or it reverts. The revert is the important half: a check is only as meaningful as the intent it is given, and an adapter that reports an uncertain result quietly leaves policy evaluating a guess.

Coverage is therefore a real constraint, not a roadmap item. A protocol that nothing decodes is not reachable under a mandate that permits approved adapters only, and widening that reach means writing and approving an adapter rather than relaxing a rule.

06Credential queries

Ask whether a condition holds, not for the evidence behind it

A mandate can require that the subject holds a credential. Evaluating that requirement means asking the passport one question, and the answer is an assertion rather than a document.

IPassportRegistry
interface IPassportRegistry {
    /// @notice Whether a subject currently holds a valid credential of a type.
    /// @dev Returns the assertion only, never the evidence behind it.
    function holdsCredential(
        address subject,
        bytes32 credentialType
    ) external view returns (bool held);

    /// @notice The issuer and validity window standing behind an assertion.
    function credentialStatus(
        address subject,
        bytes32 credentialType
    ) external view returns (
        address issuer,
        uint64 issuedAt,
        uint64 expiresAt,
        bool revoked
    );
}

An issuer performs the underlying check and attests to the result. The passport records that attestation against the subject. An integrator reads whether the condition holds and, where it matters, the issuer and validity window behind it. What the issuer examined is not part of the answer and is not held by the layer evaluating policy.

Expiry and revocation are read through the same query. An expired credential is treated as absent rather than as a warning, so time alone can withdraw an authority. A revocation takes effect across every mandate that depends on the credential, without those mandates being rewritten.

Credential queryPASS
Subject
0x3A…F02
Passport
0x7F…94A
Credential type
STOCK_TOKEN_ELIGIBLE
Held
True
Validity
Bounded window, revocable by issuer
Attestations
  • IDENTITY_VERIFIED
  • NON_US_PERSON
  • EEA_ELIGIBLE
  • AML_CHECKED
Read by policy
Only what the mandate requires
An illustrative query. The response reports that a condition is satisfied; it does not return what the issuer examined to decide that.

07Protocol lifecycle

From a grant to an accounted execution

An integration touches two steps of this path: the check, and what the caller does with the answer. The rest determine what that answer means.

  1. Mandate granted

    The party with authority defines what an actor may do on its behalf: permitted assets and actions, permitted venues, a per-transaction ceiling, a periodic exposure limit, required credentials and a validity window. The grant is a record — it can be amended, suspended or left to expire.

  2. Actor proposes

    The actor constructs a call. It holds a key, so it is able to sign. Nothing so far has established that it is permitted to.

  3. Adapter validates

    The adapter registered for the target decodes the call into an execution intent: asset, action, value, venue. If no adapter covers the target, or none can decode it with confidence, the path ends here with INVALID_EXECUTION_CONTEXT.

  4. Policy evaluates

    The intent is evaluated against the governing mandate in the defined order, stopping at the first rule that is not satisfied.

  5. Decision returned

    An outcome and a reason go back to the caller. The reason is a stable identifier, so the caller, an operator’s log and an auditor reading it later describe the same event the same way.

  6. Execution proceeds or refuses

    On AUTHORIZED the call continues to the target. On anything else the caller refuses and carries the reason with the refusal. A refusal is a completed evaluation, not a failed one.

  7. Accounting updated

    Authorized value is recorded against the mandate’s period, so the next evaluation sees the exposure that remains rather than the limit originally set. Refusals record nothing: an execution that did not happen does not consume a limit.

The sequence runs identically whether the actor is a person, a script or a model. Authority is a property of the mandate rather than of the thing holding the key.

08Continue

The specification carries the definitions

  • Integration model

    Where the check sits in a full system, and how the positions compose.

  • Specification

    Interfaces, evaluation order and the decision structure, stated precisely.

  • Security model

    What the model relies on, what it does not claim, and where trust is placed.