@leash/core is the dependency-light primitive used by both the buyer and
seller kits. It contains:
- Agent + treasury —
treasuryPda(asset)derives the Asset Signer PDA used aspayToand the on-chain owner of the agent’s funds.deriveAgentTreasuryAddress(asset)andderiveAgentTreasuryAta({ asset, mint })do the same derivations using@solana/kitonly (no Umi runtime), so buyer/seller code can resolve the treasury + token ATA without dragging in Metaplex’s Umi context. - Policy —
evaluate(rules, request, ledger, pause)returns a pure decision (allow/deny+reason). Buyer/seller kits also stamprejectedon receipts when the gate allowed a call but the payment did not settle. - Networks —
caip2ForNetwork('solana-devnet')returns the wire-level CAIP-2 chain id; the inversenetworkFromCaip2('solana:EtWTRABZ…')returns the friendly Leash slug used on receipts. - Hashing —
canonicalJson,sha256Hex,requestHash,paymentRequirementsHash,computeReceiptHash,finalizeReceipt,verifyReceiptChain. All hashing uses@noble/hashesso it runs in any JS environment (Node, browser, edge). - x402 client adapter —
createSvmBuyerFetch({ signer, networks, rpcUrl, preferredAsset?, sourceTokenAccount? })wrapswrapFetchWithPaymentfrom@x402/fetchwithExactSvmScheme(orLeashDelegateExactSvmSchemewhensourceTokenAccountis set) and aClientSvmSigner. OptionalpreferredAsset(SPL mint string) selects whichaccepts[]row to pay when the seller lists several stables; if set and no row matches, the client throws (preferred_asset_unavailable) instead of silently paying a different mint.@leash/buyer-kitwires this viapreferredCurrency(USDC/USDT/USDG). - Payment-link discovery —
fetchPaymentLinkMeta()fetches and type-checks the browser-friendlyGET /x/<id>metadata payload exposed by the web app;buildPaymentLinkMeta()produces it on the server. - Payment envelope —
buildLeashEnvelope(receipt, { origin })produces the compactLeashPaymentEnvelopethat gets stamped onto webhooks, response headers, andwrap_receiptbodies after a settled payment. X-Leash-*headers —buildLeashHeaders(envelope, headers)andparseLeashHeaders(response)round-trip the envelope through HTTP responses without sellers / buyers misspelling header names.LEASH_HEADERSis the canonical name map;LEASH_CALLBACK_HEADERis the per-call webhook opt-in (x-leash-callback).- Webhook payload —
buildWebhookPayload({ envelope, response })andparseWebhookPayload(json)produce / validate the JSON body Leash POSTs toendpoint.webhook_url. Versioned (v: '0.1') and discriminated (kind: 'leash.payment.settled') so downstream agents can route safely. - Token registry —
KNOWN_TOKENS,lookupToken(mint, network),lookupTokenBySymbol(symbol, network),KNOWN_STABLE_SYMBOLS,currencyForAsset(mint, network),pinnedMints(network),defaultUsdcMint(network). Stables on mainnet + devnet plus a few bluechips, indexed for UI surfaces. - Format helpers —
atomicToDecimal,decimalToAtomic,formatTokenBalance,formatReceiptPrice,formatReceiptPriceUsd. Use these instead of hand-rolled*1_000_000math; they pull decimals from the registry so Token-2022 stables don’t silently truncate. - Explorer links —
transactionExplorerUrl,addressExplorerUrl,agentExplorerUrl. Solscan by default; pass{ provider: 'solana-explorer' }for the official explorer. - Treasury balances —
listSplBalances({ owner, rpcUrl, network })enumerates SPL + Token-2022 balances and pins missing stables with zero so UIs always render them. - Kill switch —
readPauseFromEnv,createPauseResolver. The buyer’s policy gate honours these so a single env flip (or admin RPC) can halt every spend immediately. - Treasury helpers —
getTreasuryBalance,buildWithdrawTx(stub for v0.1).
Agent treasury PDA
Resolve an agent’s on-chain treasury (Asset Signer PDA) and its token ATA without dragging in the Umi runtime. Useful inside@leash/buyer-kit’s
auto-preflight and for any caller that needs to sign on behalf of an agent
with @solana/kit only.
["mpl-core-execute", asset]) and program id
(CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d) match Metaplex Core’s
findAssetSignerPda exactly. Pass
{ tokenProgram: TOKEN_2022_PROGRAM_ADDRESS } for Token-2022 mints; the
default is the legacy SPL Token program.
Why a separate adapter?
@x402/fetch is transport-agnostic — it doesn’t know which chain or
scheme the seller wants. We register ExactSvmScheme once, point it at
the user’s RPC, and reuse the same paidFetch for every buyer call. The
adapter is also where we set the default network list (solana-devnet,
solana-mainnet).
endpoint.currency (primary settlement ticker) and
endpoint.accepts_currencies (extra stables the seller added). The playground
buyer uses these to pre-check that Pay with matches what the link accepts.
Settlement envelope, headers, and webhooks
After a successful x402 settlement the seller/x/<id> route stamps a
compact summary onto the response. Producers + consumers share one type:
Token registry, formatters, and explorer links
Real x402 on Solana for the protocol
walkthrough and a deeper dive on the headers (PAYMENT-REQUIRED,
PAYMENT-SIGNATURE, PAYMENT-RESPONSE).
