gatePayment
Read-only policy decision call. Simulates PolicyVault's gate_payment instruction and returns the typed GateDecision union.
gatePayment() is the read-only entry point. It builds an Anchor simulation of gate_payment, parses the return-data channel into the TypeScript union, and never sends a transaction.
Use it when your facilitator already owns its x402 routing and only needs the AgentTrust decision. For atomic settlement (gate + transfer + feedback in one tx), use mountTrustGate or composeAtomicSettleTx.
Source: trustgate/sdk/src/client.ts.
Signature
import { gatePayment } from "@agenttrust-sdk/trustgate/client";
export function gatePayment(req: GatePaymentRequest): Promise<GateDecision>;GatePaymentRequest
interface GatePaymentRequest {
rpcUrl: string;
caller: Keypair; // facilitator keypair (signs simulate-tx)
payerAgentAsset: PublicKey; // payer's Metaplex Core asset (Quantu agent identity)
payeeAgentAsset: PublicKey; // payee's Metaplex Core asset
amount: bigint | number; // base units (1_000_000n = 1 USDC at 6 decimals)
mint: PublicKey; // USDC devnet: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
policyId: number; // PolicyAccount.policy_id (u32)
programIds?: ProgramIds; // defaults to DEFAULT_DEVNET_PROGRAM_IDS
}The caller keypair signs the simulation transaction; the result is never committed, so the keypair is only used to satisfy the simulate-tx fee-payer. Pass any funded devnet keypair.
GateDecision
type GateDecision =
| { kind: "Allow" }
| { kind: "Deny"; reasonCode: number; reasonName: string }
| { kind: "RequireValidation"; capabilityHash: Uint8Array /* 32 bytes */ };| Decision | Next step |
|---|---|
Allow | Proceed to settlement (build / sign / submit the atomic tx). |
Deny | Return 402 to the user with reasonName. Surface reasonCode for machine consumers. |
RequireValidation | Route the user to the attestation flow for capabilityHash. After the attestor responds, re-call gatePayment — the gate now sees the new ValidationAttestation and flips to Allow. |
reasonCode is decoupled from Borsh wire-format ordering. Full table: Reference → DenyReason codes.
Example
import { Keypair, PublicKey } from "@solana/web3.js";
import { gatePayment } from "@agenttrust-sdk/trustgate/client";
const facilitatorKey = Keypair.fromSecretKey(new Uint8Array(JSON.parse(process.env.FACILITATOR_KEY!)));
const decision = await gatePayment({
rpcUrl: "https://api.devnet.solana.com",
caller: facilitatorKey,
payerAgentAsset: new PublicKey("5PfaofvEUf3adtJwMho7zzbfvgxwxbvp2V5moqhtLK8y"),
payeeAgentAsset: new PublicKey("5PfaofvEUf3adtJwMho7zzbfvgxwxbvp2V5moqhtLK8y"),
amount: 1_000_000n, // 1 USDC
mint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
policyId: 1,
});
switch (decision.kind) {
case "Allow":
console.log("gate=Allow — proceed to settle");
break;
case "Deny":
console.log(`gate=Deny ${decision.reasonCode} (${decision.reasonName})`);
break;
case "RequireValidation":
const hex = Buffer.from(decision.capabilityHash).toString("hex");
console.log(`gate=RequireValidation capability=${hex}`);
break;
}Implementation note — return-data channel
PolicyVault's gate_payment (lazy variant) returns the decision via Anchor's set_return_data so simulation can decode it. The strict variant — used by composeAtomicSettleTx — instead returns Err on non-Allow, which is what makes the atomic tx revert as a unit.
gatePayment() simulates the lazy variant and parses the return-data via parseGateDecision. The wire format is documented in programs/policy-vault/src/state/decision.rs.
Errors
| Error | Cause |
|---|---|
AccountNotFound | PolicyAccount PDA missing for (payerAgentAsset, policyId) — call init_policy first. |
RPC error: insufficient funds | caller keypair has zero SOL. Fund via solana airdrop 1 <pubkey> --url devnet. |
IdlAccountUnsupported | Program IDL not yet published on the cluster. Run anchor idl init <programId> --provider.cluster <cluster>. |
For the atomic-settle path (which can also return AtomicityNotEnforcedError), see composeAtomicSettleTx.
Source
- Client:
trustgate/sdk/src/client.ts - Simulation:
trustgate/sdk/src/chain.ts(simulateGatePayment,parseGateDecision) - Types:
trustgate/sdk/src/types.ts - Tests:
trustgate/sdk/test/
@agenttrust-sdk/trustgate
TypeScript surface for AgentTrust on Solana — Express middleware, client helpers, atomicity guard, PDA derivers, and the full ValidationRegistry instruction builder set.
mountTrustGate
Drop-in Express middleware. Adds the four x402 routes to any app — verify, receipt, settle, dispute — with the atomicity guard enforced at compile-time and runtime.