Reference
Specification
Normative definitions of the PASS terms, the preflight procedure and the decision format.
Conformance to PASS is judged on two things: an implementation evaluates the objects defined below in the order defined below, and it returns the defined Reason Code for the first rule that fails. Both matter. An implementation that refuses the right execution for the wrong reason is not conformant, because the Reason Code, and not the refusal itself, is what an automated caller acts on next. This document is written to be implemented against.
Conventions
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119.
| Term | Meaning |
|---|---|
| MUST | An absolute requirement. A conformant implementation cannot omit it. |
| MUST NOT | An absolute prohibition. |
| SHOULD | A recommendation. Valid reasons may exist to deviate, and the full implications must be understood and weighed before doing so. |
| SHOULD NOT | A discouraged behaviour, under the same conditions as SHOULD. |
| MAY | Genuinely optional. An implementation that omits it and one that includes it must interoperate. |
Two further conventions apply throughout. First, evaluation is default-deny: any condition not explicitly permitted by a mandate is denied. An empty allow-list permits nothing; it does not permit everything. Second, evaluation is deterministic: given the same intent, mandate, passport, recorded exposure and evaluation timestamp, preflight MUST return the same outcome and the same Reason Code. No other input may affect the result.
The interface definitions in this document use protocol-level type names rather than the types of any particular language. They state the shape of an object and the obligations attached to its fields.
Terminology
Actor. The entity proposing an execution. An actor is identified by an address and demonstrates control of the corresponding key. Control of a key is not authority; an actor holds only the authority a mandate confers on it.
Subject. The party on whose behalf the actor acts and to whom credentials pertain. An actor and a subject MAY be the same party. When they differ, the mandate is the object that binds one to the other.
Issuer. An entity that issues credentials about a subject and that can revoke them. Issuers are named in policy. A mandate that requires a credential type MUST also determine which issuers of that type it accepts; accepting an unspecified issuer set is non-conformant.
Credential. An attestation about a subject. A credential MUST carry a type identifier, an issuer identifier, an issuance time and a revocation status, and MAY carry an expiry time and a payload. The architecture supports privacy-preserving credential models and external attestations: a credential MAY be presented as a proof of a claim rather than as the underlying data.
Passport. A credential container bound to a subject. A passport holds credentials and MUST be resolvable at evaluation time, so that revocation and expiry are read as of that moment. A passport does not grant authority. It describes eligibility; a mandate decides what eligibility permits.
Mandate. Machine-readable financial authority. A mandate binds an actor to a subject and states what that actor may do, over which assets, through which venues, within which limits, and until when.
Policy. The machine-enforceable rules a mandate is assembled from. A policy is a single evaluable constraint — an asset allow-list, a transaction ceiling, a credential requirement. Mandates are compositions of policies, which is what makes them comparable, auditable and revocable as a unit.
Adapter. Protocol-specific decoding that turns a raw call into a validated Execution Intent. An adapter carries the knowledge of what a given contract call means.
Execution Intent. The normalized description of a proposed execution, derived by an adapter, against which policy is evaluated. Policy is never evaluated against raw calldata.
Preflight. The evaluation of an Execution Intent against a mandate and a passport, performed before execution.
Decision. The result of preflight: an outcome, exactly one Reason Code, and a binding to the intent that was evaluated.
Reason Code. A stable enumerated identifier describing why a decision was reached. Reason Codes are part of the protocol's public surface and MUST NOT be redefined once assigned.
Execution Intent
A proposal arrives as a raw call and its context: the acting address, the mandate claimed, the passport to resolve, the target contract, the calldata and the chain. None of that is an intent. An Execution Intent MUST be constructed by an adapter before any policy is evaluated.
interface ExecutionIntent {
actor: Address; // proposer of the execution
subject: SubjectId; // party on whose behalf it acts
mandate: MandateId; // authority claimed for this execution
passport: PassportId; // credential container resolved for the subject
chainId: number; // execution environment
adapter: AdapterId; // adapter that produced this intent
target: Address; // contract the call is addressed to
action: ActionCode; // normalized action, e.g. BUY, SELL, BRIDGE
asset: AssetId; // canonical asset identifier
amount: bigint; // base units of asset
valuation: bigint; // value in the mandate's accounting unit
valuationSource: string; // reference used to derive valuation
counterparty?: Address; // where the action names one
callHash: bytes32; // commitment to the exact calldata decoded
observedAt: number; // evaluation timestamp
}Every field except counterparty is required. callHash is what binds a decision to a
specific call: a decision issued for one intent MUST NOT be treated as authority for a
call whose hash differs. valuation and valuationSource exist because limits are
denominated in value rather than in token units, and the source of that value is an
external dependency the protocol does not eliminate. observedAt fixes the one moment
the whole evaluation refers to. Credential expiry, mandate validity and the exposure
window are read as of that timestamp, not as of the moment a later step happens to run.
Mandate
interface Mandate {
id: MandateId;
actor: Address;
subject: SubjectId;
grantedBy: Address; // party that granted the mandate
status: 'ACTIVE' | 'SUSPENDED';
notBefore: number;
expiresAt: number;
accountingUnit: string; // unit for all value limits
allowedActions: ActionCode[];
allowedAssets: AssetId[];
allowedAdapters: AdapterId[];
requiredCredentials: CredentialRequirement[];
maxTransactionValue: bigint;
dailyExposureLimit: bigint;
exposureWindow: 'CALENDAR_DAY' | 'ROLLING_24H';
exposureOnFailure: 'RELEASE' | 'RETAIN';
allowedChains?: number[]; // optional from here
allowedCounterparties?: Address[];
perAssetLimits?: AssetLimit[];
version?: string;
}The fields above the blank line are required; those below are optional. Where
allowedChains is absent, an implementation MUST restrict execution to the chain the
mandate was issued for rather than infer permission for others.
exposureWindow and exposureOnFailure are required because a periodic limit without
them is under-specified. A limit of $10,000 constrains differently under a calendar
window, which resets on a boundary, than under a rolling one, which has no boundary but
requires per-intent history to compute. exposureOnFailure settles whether budget
consumed by an authorized execution that later fails downstream is released or retained.
Both answers are defensible, which is precisely why the mandate MUST state one rather
than leave it to the enforcing implementation.
The running example used throughout this documentation is expressed in exactly these
terms: actor 0x81...29F, allowed assets AAPL and NVDA, a maxTransactionValue of
$2,500, a dailyExposureLimit of $10,000, allowedAdapters limited to approved
adapters, requiredCredentials containing STOCK_TOKEN_ELIGIBLE, and BRIDGE absent
from allowedActions. Passport 0x7F...94A carries IDENTITY_VERIFIED,
NON_US_PERSON, EEA_ELIGIBLE, AML_CHECKED and STOCK_TOKEN_ELIGIBLE.
Preflight procedure
Preflight MUST evaluate the steps below in the order given. Evaluation stops at the first failing step, and that step's Reason Code is the Reason Code returned. The order runs from structural checks to economic ones: an actor that is not bound to the mandate should never receive a limit error, because that error would misdescribe the failure.
RAW CALL
|
v
CONTEXT BINDING -> INVALID_EXECUTION_CONTEXT
|
v
ADAPTER DECODE -> INVALID_EXECUTION_CONTEXT
|
v
EXECUTION INTENT
|
v
ACTOR AND MANDATE -> ACTOR_NOT_AUTHORIZED
| MANDATE_SUSPENDED
| MANDATE_EXPIRED
v
CREDENTIALS -> MISSING_CREDENTIAL
| CREDENTIAL_REVOKED
| CREDENTIAL_EXPIRED
v
SCOPE -> ACTION_NOT_ALLOWED
| ASSET_NOT_ALLOWED
| ADAPTER_NOT_ALLOWED
v
LIMITS -> TX_LIMIT_EXCEEDED
| DAILY_LIMIT_EXCEEDED
v
AUTHORIZED- Context binding. Resolve the mandate and the passport. Confirm that the chain
identifier, the evaluation timestamp and the mandate reference are internally
consistent. On failure:
INVALID_EXECUTION_CONTEXT. - Adapter decode. Select the adapter registered for the target and derive the
Execution Intent. If no adapter covers the target, or the adapter refuses to decode,
preflight MUST fail with
INVALID_EXECUTION_CONTEXT. It MUST NOT proceed on a partially decoded call. - Actor binding. The intent's actor MUST equal the mandate's actor. Otherwise:
ACTOR_NOT_AUTHORIZED. - Mandate suspension. If
statusis notACTIVE:MANDATE_SUSPENDED. Suspension is checked before expiry because it reflects a deliberate act by the party that granted the mandate and is the more actionable signal to return. - Mandate validity window. If
observedAtfalls outsidenotBeforetoexpiresAt:MANDATE_EXPIRED. - Credential presence. Every entry in
requiredCredentialsMUST be satisfied by a credential in the passport, of the required type and from an accepted issuer. Otherwise:MISSING_CREDENTIAL. - Credential revocation. If a matching credential is revoked:
CREDENTIAL_REVOKED. Revocation is checked before expiry because it is a stronger statement by the issuer about the underlying fact. - Credential expiry. If a matching credential has passed its expiry:
CREDENTIAL_EXPIRED. - Action scope. The intent's action MUST appear in
allowedActions. Otherwise:ACTION_NOT_ALLOWED. In the running example, a bridging call fails here. - Asset scope. The intent's asset MUST appear in
allowedAssets. Otherwise:ASSET_NOT_ALLOWED. - Venue scope. The intent's adapter MUST appear in
allowedAdapters, and whereallowedCounterpartiesis present the counterparty MUST appear in it. Otherwise:ADAPTER_NOT_ALLOWED. Both conditions return the same code because the registry is closed and both settle one question: where an execution is permitted to land. - Transaction limit.
valuationMUST NOT exceedmaxTransactionValue. Otherwise:TX_LIMIT_EXCEEDED. - Cumulative limit.
valuationadded to the exposure recorded against the mandate for the currentexposureWindowMUST NOT exceeddailyExposureLimit. Otherwise:DAILY_LIMIT_EXCEEDED. Only authorized intents consume the window, and reservation MUST be atomic with the decision: two intents evaluated concurrently against the same remaining budget can otherwise both pass a check only one should have passed. - If every step passes, the outcome is
AUTHORIZED.
Steps 12 and 13 depend on a valuation derived from an external reference. An
implementation that cannot obtain a valuation it trusts MUST fail with
INVALID_EXECUTION_CONTEXT before any limit is evaluated, rather than substitute a
default: a ceiling measured against a number nobody stands behind is not a ceiling. The
reasoning behind the ordering is developed in preflight.
Worked evaluations
The rows below are evaluated against the mandate of the running example.
| Proposed intent | Recorded exposure | First failing step | Reason Code |
|---|---|---|---|
| BUY, AAPL, valuation $1,800 | $4,200 | none | AUTHORIZED |
| BUY, AAPL, valuation $4,200 | $4,200 | 12, transaction limit | TX_LIMIT_EXCEEDED |
| BUY, NVDA, valuation $2,500 | $8,500 | 13, cumulative limit | DAILY_LIMIT_EXCEEDED |
| BRIDGE, AAPL, valuation $500 | $4,200 | 9, action scope | ACTION_NOT_ALLOWED |
Row one authorizes and raises recorded exposure to $6,000. Row two stops at step 12, so exposure stays at $4,200: a refused call consumes nothing. Row three clears the transaction limit, because $2,500 does not exceed $2,500, then fails the cumulative one, because $8,500 plus $2,500 is $11,000 against a limit of $10,000. Row four never reaches a limit at all. Step 9 precedes both limit checks, so the code returned describes the scope failure rather than an economic one.
Decision format
interface Decision {
outcome: 'AUTHORIZED' | 'BLOCKED';
reason: ReasonCode;
intent: bytes32; // hash of the evaluated Execution Intent
mandate: MandateId;
evaluatedAt: number;
validUntil: number; // decision MUST NOT be replayed after this
}A decision MUST carry exactly one Reason Code. A BLOCKED decision's Reason Code MUST
identify the first failing rule in the order defined above — not the most severe
failure, not an aggregate, and not a list. Aggregated failures are ambiguous to
automated callers and unstable across implementations, which defeats the purpose of a
machine-readable outcome. An AUTHORIZED decision carries the Reason Code
AUTHORIZED.
evaluatedAt MUST equal the observedAt of the intent it decides. validUntil MUST be
finite, and SHOULD be short enough that the mandate state, credential state and
valuation the decision rests on cannot plausibly have moved within it. The second row of
the table above produces:
{
"outcome": "BLOCKED",
"reason": "TX_LIMIT_EXCEEDED",
"intent": "0x9c4a...",
"mandate": "mandate:0x81...29F:1",
"evaluatedAt": 1756000000,
"validUntil": 1756000030
}A decision is a statement about one intent at one moment. Callers MUST re-run preflight
rather than reuse a decision past validUntil, or across any change to callHash.
Reason Code registry
| Reason Code | Meaning | Produced when |
|---|---|---|
| AUTHORIZED | Every rule passed. | All steps of the preflight procedure complete without failure. |
| MISSING_CREDENTIAL | A required credential is absent. | The passport holds no credential of a required type from an accepted issuer. |
| CREDENTIAL_EXPIRED | A required credential is past validity. | A matching credential exists and is not revoked, but its expiry precedes the evaluation timestamp. |
| CREDENTIAL_REVOKED | A required credential was withdrawn by its issuer. | A matching credential resolves to a revoked status. |
| ASSET_NOT_ALLOWED | The asset is outside mandate scope. | The intent's asset is absent from the mandate's allowed assets. |
| ACTION_NOT_ALLOWED | The action is outside mandate scope. | The intent's action is absent from the mandate's allowed actions. |
| ADAPTER_NOT_ALLOWED | The venue is outside mandate scope. | The intent's adapter, or its counterparty where counterparties are constrained, is not permitted by the mandate. |
| TX_LIMIT_EXCEEDED | A single execution is too large. | The intent's valuation exceeds the maximum transaction value. |
| DAILY_LIMIT_EXCEEDED | Cumulative exposure would be exceeded. | The intent's valuation added to recorded exposure for the window exceeds the daily exposure limit. |
| MANDATE_EXPIRED | The authority has lapsed. | The evaluation timestamp falls outside the mandate's validity window. |
| MANDATE_SUSPENDED | The authority is withheld. | The mandate's status is not active at evaluation time. |
| ACTOR_NOT_AUTHORIZED | The proposer is not the mandated actor. | The intent's actor does not match the mandate's actor. |
| INVALID_EXECUTION_CONTEXT | The intent could not be established. | Context binding fails, no adapter covers the target, the adapter refuses to decode, or a required valuation cannot be obtained. |
Adapter requirements
An adapter is the only component permitted to assert what a call means. That responsibility carries strict obligations.
- An adapter MUST be deterministic and free of side effects. The same calldata and context MUST produce the same intent.
- An adapter MUST derive every policy-relevant field from the call itself and from onchain state it reads directly. It MUST NOT accept a caller-supplied description of the call's meaning.
- An adapter MUST bind the intent to the exact calldata through
callHash. - An adapter MUST refuse rather than guess. If a call is ambiguous, uses an unrecognized selector, or encodes a case the adapter does not cover, it MUST return no intent. A refusal is a safe outcome; an approximate intent is not.
- An adapter MUST NOT widen authority. It reports what a call does; it never decides whether the call is permitted.
- An adapter MUST declare the actions and asset classes it can express, so that mandates can reference it precisely.
- An adapter SHOULD be versioned, and a mandate SHOULD reference adapter versions rather than adapter names alone.
The reasoning behind these rules is developed in adapters: calldata cannot be trusted to describe itself, so the component that interprets it must be constrained more tightly than the components that consume its output.
Extensibility
The protocol is designed so that new capability never silently widens existing authority. Default-deny is what makes this possible.
Credential types. New credential types are added as new identifiers. Because a
mandate lists the credentials it requires, adding a type to the ecosystem has no effect
on mandates that do not name it. An implementation MUST treat an unrecognized required
credential type as unsatisfied, producing MISSING_CREDENTIAL, rather than ignore the
requirement.
Reason Codes. New Reason Codes are additive. An assigned code's meaning MUST NOT change, and a retired code's identifier MUST NOT be reused. A consumer that receives an unrecognized Reason Code MUST treat the decision as blocked and MUST NOT infer that the execution is permitted.
Adapters. New adapters are registered against new targets. Registration alone confers nothing: an adapter becomes usable under a mandate only when that mandate lists it. A newly supported protocol therefore becomes reachable by explicit amendment, never by default.
Actions and assets. The same rule applies. Adding an action code or an asset identifier to the registry does not add it to any mandate's allow-list.
Extensions that would change the preflight ordering, the one-reason-code rule, or the default-deny posture are not extensions. They describe a different protocol.
Status of this document
This document specifies an architecture: the objects, the ordering and the outputs an implementation is required to honour. It does not claim adoption by, submission to, or endorsement from any standards body, and it makes no statement about the operational state of any system.
Its scope is authorization — who may act, what they may do, where they may execute, how much they may move, and under which conditions execution may proceed. That scope has edges. A conformant preflight does not address market risk, smart-contract risk in the venues reached through adapters, oracle risk in the valuation a limit is measured against, or governance risk in the systems that issue credentials and mandates; those are treated in security. Wallets, protocol-level validation and existing permission systems solve real problems of their own, and a mandate does not displace them. This specification addresses the narrower question of whether a given actor was permitted to do a specific thing, for a specific subject, under stated constraints. Risks outside that boundary remain with the parties who assume them.