@x1id/resolve 0.22.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +71 -0
  2. package/dist/accounts.d.ts +6 -0
  3. package/dist/accounts.js +6 -1
  4. package/dist/agent.d.ts +184 -8
  5. package/dist/agent.js +351 -3
  6. package/dist/agentPolicy.d.ts +238 -0
  7. package/dist/agentPolicy.js +364 -0
  8. package/dist/attestation.d.ts +25 -0
  9. package/dist/attestation.js +25 -0
  10. package/dist/checkout.d.ts +216 -0
  11. package/dist/checkout.js +327 -0
  12. package/dist/credentials.d.ts +466 -0
  13. package/dist/credentials.js +669 -0
  14. package/dist/gate.d.ts +94 -4
  15. package/dist/gate.js +206 -7
  16. package/dist/gateClient.d.ts +12 -0
  17. package/dist/giftLink.d.ts +272 -0
  18. package/dist/giftLink.js +452 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.js +33 -0
  21. package/dist/loginButton.d.ts +69 -0
  22. package/dist/loginButton.js +207 -0
  23. package/dist/logo.d.ts +1 -0
  24. package/dist/logo.js +8 -0
  25. package/dist/messaging.d.ts +439 -0
  26. package/dist/messaging.js +979 -0
  27. package/dist/mintNft.d.ts +247 -0
  28. package/dist/mintNft.js +328 -0
  29. package/dist/nsGate.d.ts +98 -0
  30. package/dist/nsGate.js +172 -0
  31. package/dist/oidc.d.ts +272 -0
  32. package/dist/oidc.js +641 -0
  33. package/dist/pay.d.ts +513 -0
  34. package/dist/pay.js +756 -0
  35. package/dist/payment.d.ts +9 -2
  36. package/dist/payment.js +9 -2
  37. package/dist/recovery.d.ts +186 -0
  38. package/dist/recovery.js +276 -0
  39. package/dist/recoveryNft.d.ts +183 -0
  40. package/dist/recoveryNft.js +291 -0
  41. package/dist/shield.d.ts +373 -0
  42. package/dist/shield.js +695 -0
  43. package/dist/subscription.d.ts +439 -0
  44. package/dist/subscription.js +642 -0
  45. package/dist/textRecords.d.ts +52 -6
  46. package/dist/textRecords.js +80 -8
  47. package/dist/types.d.ts +3 -0
  48. package/dist/x402Receipt.d.ts +246 -0
  49. package/dist/x402Receipt.js +374 -0
  50. package/package.json +18 -1
  51. package/schema/agent-manifest.json +91 -8
package/dist/agent.js CHANGED
@@ -24,6 +24,8 @@
24
24
  * that reports a level shares one vocabulary.
25
25
  */
26
26
  import { X1_TESTNET_NETWORK, X1_MAINNET_NETWORK } from "./x402.js";
27
+ import { paymentAddressFor } from "./payment.js";
28
+ import { CHAIN_COIN_TYPE } from "./types.js";
27
29
  // ---------------------------------------------------------------------------
28
30
  // Well-known text-record keys
29
31
  // ---------------------------------------------------------------------------
@@ -38,9 +40,33 @@ export const AGENT_RECORD_KEYS = Object.freeze({
38
40
  attestation: "agent.attestation",
39
41
  capabilities: "agent.capabilities",
40
42
  });
43
+ /** Manifest versions {@link validateManifest} accepts. v1 is the original
44
+ * shape; v2 (`docs/agent-records.md` §3.1) adds per-capability / per-endpoint
45
+ * pricing, accepted payment methods and a name-bound `payTo`. A v1 manifest
46
+ * validates exactly as it always did. */
47
+ export const AGENT_MANIFEST_VERSIONS = Object.freeze([1, 2]);
48
+ /** Billing units a v2 price may use. `per-call` is the x402 "exact" unit; the
49
+ * rest are metered units the seller's live 402 quotes per request. */
50
+ export const AGENT_PRICE_UNITS = Object.freeze([
51
+ "per-call",
52
+ "per-1k-tokens",
53
+ "per-1k-chars",
54
+ "per-minute",
55
+ "per-mb",
56
+ ]);
57
+ /** The native-asset sentinel for {@link AgentPrice.mint}: XNT on X1. */
58
+ export const AGENT_NATIVE_MINT = "XNT";
41
59
  const HTTPS_RE = /^https:\/\/[^\s@/]+(\/[^\s]*)?$/;
42
60
  const IPFS_RE = /^ipfs:\/\/[^\s]+$/;
43
61
  const BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
62
+ const EVM_ADDR_RE = /^0x[0-9a-fA-F]{40}$/;
63
+ /** v2 id grammar (capability / endpoint / method ids): a lowercase slug. */
64
+ export const AGENT_ID_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/;
65
+ const CAIP2_RE = /^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,64}$/;
66
+ const U64_MAX = 18446744073709551615n;
67
+ const MAX_V2_CAPABILITIES = 64;
68
+ const MAX_V2_METHODS = 8;
69
+ const MAX_V2_PRICES = 8;
44
70
  /** URL rule (`docs/agent-records.md` §2): every URL field is `https://`
45
71
  * ONLY, except `agent.manifest`'s own record value, which may also be
46
72
  * `ipfs://<cid>` (`allowIpfs`). */
@@ -64,7 +90,8 @@ export function validateManifest(raw, opts) {
64
90
  if (typeof x1id !== "object" || x1id === null) {
65
91
  return { ok: false, errors: [{ code: "missing-field", field: "x1id" }] };
66
92
  }
67
- if (x1id.version !== 1)
93
+ const version = x1id.version;
94
+ if (version !== 1 && version !== 2)
68
95
  errors.push({ code: "bad-version" });
69
96
  if (x1id.name !== opts.expectedName)
70
97
  errors.push({ code: "name-mismatch" });
@@ -89,7 +116,11 @@ export function validateManifest(raw, opts) {
89
116
  }
90
117
  const capabilities = m.capabilities;
91
118
  if (capabilities !== undefined) {
92
- if (typeof capabilities.url !== "string" || !checkAgentUrl(capabilities.url, false)) {
119
+ // v1: `url` is required. v2: `url` OR `items` (a manifest may list its
120
+ // capabilities inline instead of pointing at a separate document).
121
+ const urlOptional = version === 2 && capabilities.items !== undefined;
122
+ if (!(urlOptional && capabilities.url === undefined) &&
123
+ (typeof capabilities.url !== "string" || !checkAgentUrl(capabilities.url, false))) {
93
124
  errors.push({ code: "bad-url", field: "capabilities.url" });
94
125
  }
95
126
  if (capabilities.schema !== undefined &&
@@ -128,11 +159,325 @@ export function validateManifest(raw, opts) {
128
159
  }
129
160
  }
130
161
  }
162
+ if (version === 2)
163
+ validateV2(m, x1id, errors);
131
164
  if (errors.length > 0)
132
165
  return { ok: false, errors };
133
166
  return { ok: true, manifest: raw };
134
167
  }
135
168
  // ---------------------------------------------------------------------------
169
+ // v2: pricing, payment methods, name-bound payTo
170
+ // ---------------------------------------------------------------------------
171
+ function isObj(v) {
172
+ return typeof v === "object" && v !== null && !Array.isArray(v);
173
+ }
174
+ /** `amount` is a u64 decimal string of smallest units (no sign, no decimal
175
+ * point, no leading zeros except "0"). */
176
+ function checkAmount(v) {
177
+ if (typeof v !== "string" || !/^(0|[1-9][0-9]{0,19})$/.test(v))
178
+ return false;
179
+ return BigInt(v) <= U64_MAX;
180
+ }
181
+ /** A price/asset mint spelling: the native sentinel, an SVM mint, or (CDP
182
+ * rail only) an EVM token address. */
183
+ function checkMint(v) {
184
+ return typeof v === "string" && (v === AGENT_NATIVE_MINT || BASE58_RE.test(v) || EVM_ADDR_RE.test(v));
185
+ }
186
+ function checkPrices(raw, field, errors, out) {
187
+ if (raw === undefined)
188
+ return;
189
+ if (!Array.isArray(raw) || raw.length === 0 || raw.length > MAX_V2_PRICES) {
190
+ errors.push({ code: "bad-field", field });
191
+ return;
192
+ }
193
+ for (const p of raw) {
194
+ if (!isObj(p)) {
195
+ errors.push({ code: "bad-price", field });
196
+ continue;
197
+ }
198
+ if (!checkAmount(p.amount))
199
+ errors.push({ code: "bad-price", field: `${field}[].amount` });
200
+ if (!checkMint(p.mint))
201
+ errors.push({ code: "bad-price", field: `${field}[].mint` });
202
+ if (typeof p.unit !== "string" || !AGENT_PRICE_UNITS.includes(p.unit)) {
203
+ errors.push({ code: "bad-price", field: `${field}[].unit` });
204
+ }
205
+ if (checkAmount(p.amount) && checkMint(p.mint))
206
+ out.push(p);
207
+ }
208
+ }
209
+ /** Expected X1 x402 network id for a manifest's declared cluster. */
210
+ function x1NetworkFor(cluster) {
211
+ return cluster === "testnet" ? X1_TESTNET_NETWORK : X1_MAINNET_NETWORK;
212
+ }
213
+ /** Does `method` settle `mint`? An explicit `assets` list is authoritative;
214
+ * otherwise the x1 rail settles XNT or any SPL mint, and the cdp rail
215
+ * anything but native XNT. */
216
+ function methodSettles(method, mint) {
217
+ if (method.assets)
218
+ return method.assets.includes(mint);
219
+ if (method.rail === "x1")
220
+ return mint === AGENT_NATIVE_MINT || BASE58_RE.test(mint);
221
+ return mint !== AGENT_NATIVE_MINT;
222
+ }
223
+ function validateV2(m, x1id, errors) {
224
+ const prices = [];
225
+ // endpoints[]: optional id (unique), capabilities[] refs, pricing[].
226
+ const endpointIds = new Set();
227
+ const endpointCapRefs = [];
228
+ if (m.endpoints !== undefined && !Array.isArray(m.endpoints))
229
+ errors.push({ code: "bad-field", field: "endpoints" });
230
+ const endpoints = Array.isArray(m.endpoints) ? m.endpoints : [];
231
+ endpoints.forEach((e) => {
232
+ if (!isObj(e))
233
+ return;
234
+ if (e.id !== undefined) {
235
+ if (typeof e.id !== "string" || !AGENT_ID_RE.test(e.id))
236
+ errors.push({ code: "bad-id", field: "endpoints[].id" });
237
+ else if (endpointIds.has(e.id))
238
+ errors.push({ code: "duplicate-id", field: "endpoints[].id", id: e.id });
239
+ else
240
+ endpointIds.add(e.id);
241
+ }
242
+ if (e.capabilities !== undefined) {
243
+ if (!Array.isArray(e.capabilities) || e.capabilities.length > MAX_V2_CAPABILITIES) {
244
+ errors.push({ code: "bad-field", field: "endpoints[].capabilities" });
245
+ }
246
+ else {
247
+ for (const c of e.capabilities) {
248
+ if (typeof c !== "string" || !AGENT_ID_RE.test(c))
249
+ errors.push({ code: "bad-id", field: "endpoints[].capabilities[]" });
250
+ else
251
+ endpointCapRefs.push(c);
252
+ }
253
+ }
254
+ }
255
+ checkPrices(e.pricing, "endpoints[].pricing", errors, prices);
256
+ });
257
+ // capabilities.items[]: id (unique), description, endpoint ref, pricing[].
258
+ const capIds = new Set();
259
+ const caps = isObj(m.capabilities) ? m.capabilities : undefined;
260
+ const items = caps?.items;
261
+ if (items !== undefined) {
262
+ if (!Array.isArray(items) || items.length > MAX_V2_CAPABILITIES) {
263
+ errors.push({ code: "bad-field", field: "capabilities.items" });
264
+ }
265
+ else {
266
+ for (const it of items) {
267
+ if (!isObj(it)) {
268
+ errors.push({ code: "bad-field", field: "capabilities.items[]" });
269
+ continue;
270
+ }
271
+ if (typeof it.id !== "string" || !AGENT_ID_RE.test(it.id)) {
272
+ errors.push({ code: "bad-id", field: "capabilities.items[].id" });
273
+ }
274
+ else if (capIds.has(it.id)) {
275
+ errors.push({ code: "duplicate-id", field: "capabilities.items[].id", id: it.id });
276
+ }
277
+ else
278
+ capIds.add(it.id);
279
+ if (it.description !== undefined && (typeof it.description !== "string" || it.description.length > 512)) {
280
+ errors.push({ code: "bad-field", field: "capabilities.items[].description" });
281
+ }
282
+ if (it.endpoint !== undefined) {
283
+ if (typeof it.endpoint !== "string" || !AGENT_ID_RE.test(it.endpoint)) {
284
+ errors.push({ code: "bad-id", field: "capabilities.items[].endpoint" });
285
+ }
286
+ else if (!endpointIds.has(it.endpoint)) {
287
+ errors.push({ code: "unknown-endpoint", id: it.endpoint });
288
+ }
289
+ }
290
+ checkPrices(it.pricing, "capabilities.items[].pricing", errors, prices);
291
+ }
292
+ }
293
+ }
294
+ // An endpoint's capability refs must exist when the manifest lists items
295
+ // inline. (Without items, endpoint tags are free-standing search tags.)
296
+ if (Array.isArray(items)) {
297
+ for (const ref of new Set(endpointCapRefs))
298
+ if (!capIds.has(ref))
299
+ errors.push({ code: "unknown-capability", id: ref });
300
+ }
301
+ // payment.payTo / payment.methods.
302
+ const payment = isObj(m.payment) ? m.payment : undefined;
303
+ const payTo = payment?.payTo;
304
+ if (payTo !== undefined) {
305
+ if (!isObj(payTo) || Object.keys(payTo).some((k) => k !== "name")) {
306
+ errors.push({ code: "free-form-payto" });
307
+ }
308
+ else if (typeof payTo.name !== "string" || payTo.name.replace(/^@/, "") !== x1id.name) {
309
+ errors.push({ code: "payto-name-mismatch" });
310
+ }
311
+ }
312
+ const methods = [];
313
+ const rawMethods = payment?.methods;
314
+ if (rawMethods !== undefined) {
315
+ if (!Array.isArray(rawMethods) || rawMethods.length === 0 || rawMethods.length > MAX_V2_METHODS) {
316
+ errors.push({ code: "bad-field", field: "payment.methods" });
317
+ }
318
+ else {
319
+ const ids = new Set();
320
+ for (const pm of rawMethods) {
321
+ if (!isObj(pm)) {
322
+ errors.push({ code: "bad-payment-method", field: "payment.methods[]" });
323
+ continue;
324
+ }
325
+ let ok = true;
326
+ if (pm.id !== undefined) {
327
+ if (typeof pm.id !== "string" || !AGENT_ID_RE.test(pm.id)) {
328
+ errors.push({ code: "bad-id", field: "payment.methods[].id" });
329
+ ok = false;
330
+ }
331
+ else if (ids.has(pm.id)) {
332
+ errors.push({ code: "duplicate-id", field: "payment.methods[].id", id: pm.id });
333
+ }
334
+ else
335
+ ids.add(pm.id);
336
+ }
337
+ if (pm.type !== "x402") {
338
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].type" });
339
+ ok = false;
340
+ }
341
+ if (pm.rail !== "x1" && pm.rail !== "cdp") {
342
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].rail" });
343
+ ok = false;
344
+ }
345
+ if (typeof pm.network !== "string" || !CAIP2_RE.test(pm.network)) {
346
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].network" });
347
+ ok = false;
348
+ }
349
+ else if (pm.rail === "x1" && pm.network !== x1NetworkFor(x1id.network)) {
350
+ // The X1-native rail settles on THIS manifest's cluster only.
351
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].network" });
352
+ ok = false;
353
+ }
354
+ if (pm.scheme !== undefined && pm.scheme !== "exact") {
355
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].scheme" });
356
+ ok = false;
357
+ }
358
+ if (pm.facilitator !== undefined && (typeof pm.facilitator !== "string" || !checkAgentUrl(pm.facilitator, false))) {
359
+ errors.push({ code: "bad-url", field: "payment.methods[].facilitator" });
360
+ ok = false;
361
+ }
362
+ if (pm.assets !== undefined) {
363
+ if (!Array.isArray(pm.assets) || pm.assets.length === 0 || pm.assets.length > 16 || !pm.assets.every(checkMint)) {
364
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].assets" });
365
+ ok = false;
366
+ }
367
+ else if (pm.rail === "x1" && pm.assets.some((a) => EVM_ADDR_RE.test(a))) {
368
+ errors.push({ code: "bad-payment-method", field: "payment.methods[].assets" });
369
+ ok = false;
370
+ }
371
+ }
372
+ if (ok)
373
+ methods.push(pm);
374
+ }
375
+ }
376
+ }
377
+ // Anything priced ⇒ a name-bound payTo AND at least one method that
378
+ // settles each priced mint.
379
+ if (prices.length > 0) {
380
+ if (payTo === undefined)
381
+ errors.push({ code: "missing-payto" });
382
+ if (rawMethods === undefined)
383
+ errors.push({ code: "missing-payment-method" });
384
+ else if (methods.length > 0) {
385
+ for (const mint of new Set(prices.map((p) => p.mint))) {
386
+ if (!methods.some((pm) => methodSettles(pm, mint)))
387
+ errors.push({ code: "unsupported-price-mint", mint });
388
+ }
389
+ }
390
+ }
391
+ }
392
+ // ---------------------------------------------------------------------------
393
+ // v2 readers — capability ids, offers, name-bound payTo resolution
394
+ // ---------------------------------------------------------------------------
395
+ /** Every capability id a (validated) manifest advertises: v2 `items[].id`
396
+ * plus endpoint tags, deduped, in first-seen order. `[]` for v1. Used by the
397
+ * directory to index capability search. */
398
+ export function manifestCapabilities(manifest) {
399
+ if (manifest.x1id.version !== 2)
400
+ return [];
401
+ const out = new Set();
402
+ for (const it of manifest.capabilities?.items ?? [])
403
+ out.add(it.id);
404
+ for (const e of manifest.endpoints ?? [])
405
+ for (const c of e.capabilities ?? [])
406
+ out.add(c);
407
+ return [...out];
408
+ }
409
+ /** Flatten a v2 manifest's prices into offers. `[]` for v1. */
410
+ export function manifestOffers(manifest) {
411
+ if (manifest.x1id.version !== 2)
412
+ return [];
413
+ const byId = new Map();
414
+ for (const e of manifest.endpoints ?? [])
415
+ if (e.id)
416
+ byId.set(e.id, e);
417
+ const out = [];
418
+ for (const it of manifest.capabilities?.items ?? []) {
419
+ const ep = it.endpoint ? byId.get(it.endpoint) : undefined;
420
+ for (const price of it.pricing ?? []) {
421
+ out.push({ capability: it.id, endpoint: it.endpoint ?? null, url: ep?.url ?? null, endpointType: ep?.type ?? null, price });
422
+ }
423
+ }
424
+ for (const e of manifest.endpoints ?? []) {
425
+ for (const price of e.pricing ?? []) {
426
+ out.push({ capability: null, endpoint: e.id ?? null, url: e.url, endpointType: e.type, price });
427
+ }
428
+ }
429
+ return out;
430
+ }
431
+ /** The chain a payment method settles on, for the W16 rule. `null` = a
432
+ * network the rule cannot resolve (the method is then flagged unpayable). */
433
+ export function paymentMethodChain(method) {
434
+ if (method.rail === "x1")
435
+ return "X1";
436
+ if (method.network === X1_TESTNET_NETWORK || method.network === X1_MAINNET_NETWORK)
437
+ return "X1";
438
+ if (method.network.startsWith("solana:"))
439
+ return "SOL";
440
+ if (method.network.startsWith("eip155:"))
441
+ return "ETH";
442
+ return null;
443
+ }
444
+ /**
445
+ * Resolve a v2 manifest's payTo per payment method from the CHAIN — never from
446
+ * the manifest. `records` are the payTo name's decoded address records,
447
+ * `authority` its current authority (owner / pNFT holder), exactly the inputs
448
+ * of {@link paymentAddressFor} (W16, the program's `name_pays_to`).
449
+ *
450
+ * The owner fallback is only meaningful on SVM chains (X1 / SOL — the
451
+ * authority is an SVM key); on ETH only a live VERIFIED record pays, else the
452
+ * method has no address (`no-verified-record`), never the owner's SVM key.
453
+ */
454
+ export function resolveManifestPayTo(manifest, input) {
455
+ const methods = manifest.payment?.methods ?? [];
456
+ return methods.map((method) => {
457
+ const chain = paymentMethodChain(method);
458
+ if (chain === null)
459
+ return { method, chain, payTo: null, reason: "unsupported-network" };
460
+ const svm = chain === "X1" || chain === "SOL";
461
+ const payTo = paymentAddressFor(input.records, svm ? input.authority : null, chain);
462
+ if (payTo)
463
+ return { method, chain, payTo };
464
+ return { method, chain, payTo: null, reason: svm ? "no-authority" : "no-verified-record" };
465
+ });
466
+ }
467
+ /** Flag every `payment.addresses[]` mirror entry (v1 or v2) whose chain has a
468
+ * W16-resolved address that differs. `resolved` maps chain → the address
469
+ * {@link paymentAddressFor} returned for the name. */
470
+ export function payToWarnings(manifest, resolved) {
471
+ const out = [];
472
+ for (const a of manifest.payment?.addresses ?? []) {
473
+ const chain = Object.keys(CHAIN_COIN_TYPE).find((c) => CHAIN_COIN_TYPE[c] === a.coinType);
474
+ const r = chain ? resolved[chain] : undefined;
475
+ if (r !== undefined && r !== a.address)
476
+ out.push({ code: "payto-diverges", coinType: a.coinType, claimed: a.address, resolved: r });
477
+ }
478
+ return out;
479
+ }
480
+ // ---------------------------------------------------------------------------
136
481
  // Reading agent text records off a handle's already-fetched records
137
482
  // ---------------------------------------------------------------------------
138
483
  /** Pick the agent-related well-known keys out of a handle's live text
@@ -193,7 +538,10 @@ export function x402AcceptsFromManifest(manifest, opts) {
193
538
  // matching id — "testnet" → X1_TESTNET_NETWORK, anything else (mainnet, the
194
539
  // production default) → X1_MAINNET_NETWORK.
195
540
  const network = x402?.network ?? (manifest.x1id.network === "testnet" ? X1_TESTNET_NETWORK : X1_MAINNET_NETWORK);
196
- const payTo = opts?.payTo ?? manifest.payment?.addresses?.[0]?.address;
541
+ // v2 NEVER takes a payTo from the manifest: it names an @name and the
542
+ // caller resolves the address from the chain (resolveManifestPayTo). Only
543
+ // the legacy v1 shape falls back to its self-reported address mirror.
544
+ const payTo = opts?.payTo ?? (manifest.x1id.version === 2 ? undefined : manifest.payment?.addresses?.[0]?.address);
197
545
  return x402Endpoints.map((e) => {
198
546
  const hint = {
199
547
  scheme: x402?.scheme ?? "exact",
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Agent spend policies enforced by the registry (program upgrade 6,
3
+ * OpenProject #8456; spec docs/specs/agent-spend-policy.md).
4
+ *
5
+ * The current authority of an `@name` (untokenized owner, or the pNFT holder)
6
+ * authorises an agent wallet under a policy bound to the name:
7
+ * `["agent_policy", handle, agent]` holds per-mint caps per rolling period
8
+ * (native XNT = {@link AGENT_POLICY_NATIVE_MINT}), an expiry and an optional
9
+ * recipient allow-list. Native XNT is spent from the policy PDA's float (its
10
+ * lamports above rent); SPL / Token-2022 from a grantor token account through
11
+ * the policy's OWN delegate `["agent_delegate", policy, createdSlot]`, which
12
+ * the grantor approves with a plain SPL `Approve`
13
+ * ({@link buildApproveAgentDelegateIx}). One delegate per policy (Sentinel
14
+ * run-012 A-04): an allowance approved for one agent's policy can never be
15
+ * spent by another agent. One delegate per CREATION (D-02): the policy's
16
+ * `createdSlot` is a seed, so an approval left behind by a revoked policy
17
+ * can never re-arm when the same `(handle, agent)` policy is created again. A token account has
18
+ * one delegate, so give each agent (policy) its own token account per mint.
19
+ *
20
+ * Kill switches: lock the name (`lock_handle`, lock.ts) — every spend fails
21
+ * at once; {@link buildRevokeAgentPolicyIx} (works during lockdown and while
22
+ * locked); {@link buildWithdrawAgentFloatIx}; SPL `Revoke`.
23
+ *
24
+ * Tokenized names: pass `holderTokenAccount` (the grantor's canonical pNFT ATA)
25
+ * to create / update / spend; it is the program's `remaining_accounts[0]`
26
+ * authority proof.
27
+ *
28
+ * Hand-rolled like the rest of this package: no Anchor client, no web3.js.
29
+ */
30
+ import type { AddressLike, BuiltInstruction } from "./delegate.js";
31
+ import type { PdaFinder } from "./namespacePricing.js";
32
+ export declare const AGENT_POLICY_SEED = "agent_policy";
33
+ export declare const AGENT_DELEGATE_SEED = "agent_delegate";
34
+ /** The "mint" a native-XNT cap is written under (all-zero pubkey). */
35
+ export declare const AGENT_POLICY_NATIVE_MINT = "11111111111111111111111111111111";
36
+ export declare const AGENT_MAX_CAPS = 4;
37
+ export declare const AGENT_MAX_RECIPIENTS = 4;
38
+ export declare const AGENT_PERIOD_MIN_SECS = 60;
39
+ export declare const AGENT_PERIOD_MAX_SECS: number;
40
+ /** `8 + AgentPolicy::INIT_SPACE` (layout v2: `created_slot` appended). */
41
+ export declare const AGENT_POLICY_ACCOUNT_LEN = 525;
42
+ /** `AGENT_POLICY_VERSION` of the accounts this decoder reads. */
43
+ export declare const AGENT_POLICY_LAYOUT_VERSION = 2;
44
+ /** `sha256("global:<name>")[0..8]`, pinned + re-derived in the tests. */
45
+ export declare const CREATE_AGENT_POLICY_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
46
+ export declare const UPDATE_AGENT_POLICY_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
47
+ export declare const FUND_AGENT_POLICY_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
48
+ export declare const WITHDRAW_AGENT_FLOAT_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
49
+ export declare const REVOKE_AGENT_POLICY_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
50
+ export declare const AGENT_SPEND_NATIVE_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
51
+ export declare const AGENT_SPEND_SPL_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
52
+ /** `sha256("account:AgentPolicy")[0..8]`. */
53
+ export declare const AGENT_POLICY_ACCOUNT_DISCRIMINATOR: Uint8Array<ArrayBuffer>;
54
+ /** Program error codes (AgentPolicyError, offset 6190). */
55
+ export declare const AGENT_POLICY_ERRORS: Readonly<Record<number, string>>;
56
+ /** `["agent_policy", handle, agent]`. */
57
+ export declare function deriveAgentPolicyPda(find: PdaFinder, programId: AddressLike, handle: AddressLike, agent: AddressLike): Promise<string>;
58
+ /**
59
+ * `["agent_delegate", policy, createdSlot (u64 LE)]` — the policy's own SPL
60
+ * delegate, which the grantor approves on the token account that policy's
61
+ * agent spends from. `createdSlot` is the policy's generation: read it from
62
+ * the account ({@link decodeAgentPolicy}`(…).createdSlot`) after
63
+ * `create_agent_policy` lands. A re-created policy (same address) has a new
64
+ * `createdSlot`, hence a new delegate (Sentinel run-012 D-02). Since 0.41.0;
65
+ * 0.40 used `["agent_delegate", policy]`, 0.38–0.39 the grantor (neither on
66
+ * mainnet).
67
+ */
68
+ export declare function deriveAgentDelegatePda(find: PdaFinder, programId: AddressLike, agentPolicy: AddressLike, createdSlot: bigint): Promise<string>;
69
+ export interface AgentCap {
70
+ /** SPL / Token-2022 mint, or {@link AGENT_POLICY_NATIVE_MINT} for native XNT. */
71
+ readonly mint: AddressLike;
72
+ /** Max base units per period (> 0). */
73
+ readonly cap: bigint;
74
+ }
75
+ export interface AgentPolicyTerms {
76
+ /** Unix seconds; must be in the future. */
77
+ readonly expiresAt: bigint;
78
+ readonly periodSecs: bigint;
79
+ /** 1..=4 caps, unique mints. */
80
+ readonly caps: readonly AgentCap[];
81
+ /** 0..=4 recipients; empty = any recipient. */
82
+ readonly recipients?: readonly AddressLike[];
83
+ }
84
+ /** Client-side mirror of the program's `validate_terms` (null = valid). */
85
+ export declare function agentPolicyTermsProblem(t: AgentPolicyTerms, nowSecs: bigint): string | null;
86
+ /** Borsh `AgentPolicyTerms { expires_at, period_secs, caps: Vec<{mint,cap}>, recipients: Vec<Pubkey> }`. */
87
+ export declare function encodeAgentPolicyTerms(t: AgentPolicyTerms): Uint8Array;
88
+ interface Common {
89
+ readonly programId: AddressLike;
90
+ }
91
+ interface WithProof {
92
+ /** Tokenized name: the grantor's canonical pNFT ATA (authority proof). */
93
+ readonly holderTokenAccount?: AddressLike;
94
+ }
95
+ export interface CreateAgentPolicyParams extends Common, WithProof {
96
+ readonly grantor: AddressLike;
97
+ readonly handle: AddressLike;
98
+ readonly config: AddressLike;
99
+ /** {@link deriveAgentPolicyPda}(handle, agent). */
100
+ readonly agentPolicy: AddressLike;
101
+ readonly agent: AddressLike;
102
+ readonly terms: AgentPolicyTerms;
103
+ /** For the client-side check; defaults to the local clock. */
104
+ readonly nowSecs?: bigint;
105
+ }
106
+ /** `create_agent_policy(agent, terms)`: grantor(s,w), handle, config, agent_policy(w), system [+ holder ATA]. */
107
+ export declare function buildCreateAgentPolicyIx(p: CreateAgentPolicyParams): BuiltInstruction;
108
+ export interface UpdateAgentPolicyParams extends Common, WithProof {
109
+ readonly grantor: AddressLike;
110
+ readonly handle: AddressLike;
111
+ readonly config: AddressLike;
112
+ readonly agentPolicy: AddressLike;
113
+ readonly terms: AgentPolicyTerms;
114
+ readonly nowSecs?: bigint;
115
+ }
116
+ /** `update_agent_policy(terms)`: grantor(s), handle, config, agent_policy(w) [+ holder ATA]. */
117
+ export declare function buildUpdateAgentPolicyIx(p: UpdateAgentPolicyParams): BuiltInstruction;
118
+ export interface FundAgentPolicyParams extends Common {
119
+ readonly grantor: AddressLike;
120
+ readonly config: AddressLike;
121
+ readonly agentPolicy: AddressLike;
122
+ readonly lamports: bigint;
123
+ }
124
+ /** `fund_agent_policy(amount)`: grantor(s,w), config, agent_policy(w), system. */
125
+ export declare function buildFundAgentPolicyIx(p: FundAgentPolicyParams): BuiltInstruction;
126
+ export interface WithdrawAgentFloatParams extends Common {
127
+ readonly grantor: AddressLike;
128
+ readonly agentPolicy: AddressLike;
129
+ readonly lamports: bigint;
130
+ }
131
+ /** `withdraw_agent_float(amount)`: grantor(s,w), agent_policy(w). Always allowed. */
132
+ export declare function buildWithdrawAgentFloatIx(p: WithdrawAgentFloatParams): BuiltInstruction;
133
+ export interface RevokeAgentPolicyParams extends Common, WithProof {
134
+ /** Grantor, agent, the name's current authority (with `holderTokenAccount`
135
+ * if tokenized), or anyone once the policy is expired / stale. */
136
+ readonly signer: AddressLike;
137
+ readonly handle: AddressLike;
138
+ readonly agentPolicy: AddressLike;
139
+ /** `policy.grantor` — receives every lamport. */
140
+ readonly grantor: AddressLike;
141
+ }
142
+ /** `revoke_agent_policy()`: signer(s), handle, agent_policy(w), grantor(w) [+ signer's pNFT ATA]. */
143
+ export declare function buildRevokeAgentPolicyIx(p: RevokeAgentPolicyParams): BuiltInstruction;
144
+ export interface AgentSpendNativeParams extends Common, WithProof {
145
+ readonly agent: AddressLike;
146
+ readonly agentPolicy: AddressLike;
147
+ readonly handle: AddressLike;
148
+ readonly config: AddressLike;
149
+ readonly recipient: AddressLike;
150
+ readonly lamports: bigint;
151
+ }
152
+ /** `agent_spend_native(amount)`: agent(s), agent_policy(w), handle, config, recipient(w) [+ grantor's pNFT ATA]. */
153
+ export declare function buildAgentSpendNativeIx(p: AgentSpendNativeParams): BuiltInstruction;
154
+ export interface AgentSpendSplParams extends Common, WithProof {
155
+ readonly agent: AddressLike;
156
+ readonly agentPolicy: AddressLike;
157
+ readonly handle: AddressLike;
158
+ readonly config: AddressLike;
159
+ /** {@link deriveAgentDelegatePda}(agentPolicy, createdSlot) — this policy's own delegate. */
160
+ readonly agentDelegate: AddressLike;
161
+ readonly mint: AddressLike;
162
+ /** A grantor-owned token account approved to `agentDelegate`. */
163
+ readonly source: AddressLike;
164
+ /** The recipient's token account (its OWNER is checked against the allow-list). */
165
+ readonly destination: AddressLike;
166
+ /** SPL Token or Token-2022 (the mint's owner). */
167
+ readonly tokenProgram: AddressLike;
168
+ readonly amount: bigint;
169
+ }
170
+ /** `agent_spend_spl(amount)`: agent(s), agent_policy(w), handle, config, agent_delegate, mint, source(w), destination(w), token_program [+ grantor's pNFT ATA]. */
171
+ export declare function buildAgentSpendSplIx(p: AgentSpendSplParams): BuiltInstruction;
172
+ export interface ApproveAgentDelegateParams {
173
+ readonly tokenProgram: AddressLike;
174
+ /** The grantor's token account the agent will spend from. */
175
+ readonly source: AddressLike;
176
+ /** {@link deriveAgentDelegatePda}(agentPolicy, createdSlot) of the ONE policy (creation) this allowance is for. */
177
+ readonly agentDelegate: AddressLike;
178
+ readonly grantor: AddressLike;
179
+ /** The SPL allowance (the outer bound; the policy cap is the inner one). */
180
+ readonly amount: bigint;
181
+ }
182
+ /** SPL `Approve` (tag 4) of the agent delegate — signed by the grantor. */
183
+ export declare function buildApproveAgentDelegateIx(p: ApproveAgentDelegateParams): BuiltInstruction;
184
+ /**
185
+ * SPL `Revoke` (tag 5) — the grantor cuts the policy whose delegate is
186
+ * approved on that token account off it. `revoke_agent_policy` closes the
187
+ * policy but cannot clear the SPL approval (only the token-account owner
188
+ * can). The leftover approval names a delegate no policy can ever sign as
189
+ * again (re-creating the same `(handle, agent)` policy gets a new
190
+ * `createdSlot` and a new delegate), so an old approval can never re-arm;
191
+ * appending this still tidies the token account (it holds one delegate).
192
+ */
193
+ export declare function buildRevokeAgentDelegateIx(p: {
194
+ readonly tokenProgram: AddressLike;
195
+ readonly source: AddressLike;
196
+ readonly grantor: AddressLike;
197
+ }): BuiltInstruction;
198
+ export interface AgentMintCapState {
199
+ readonly mint: string;
200
+ readonly native: boolean;
201
+ readonly cap: bigint;
202
+ readonly spent: bigint;
203
+ readonly periodStart: bigint;
204
+ }
205
+ export interface AgentPolicyAccount {
206
+ readonly version: number;
207
+ readonly bump: number;
208
+ readonly delegateBump: number;
209
+ readonly handle: string;
210
+ readonly agent: string;
211
+ readonly grantor: string;
212
+ /** `max(registered_at, holder_epoch)` at grant. */
213
+ readonly epoch: bigint;
214
+ readonly createdAt: bigint;
215
+ readonly updatedAt: bigint;
216
+ readonly expiresAt: bigint;
217
+ readonly periodSecs: bigint;
218
+ readonly caps: readonly AgentMintCapState[];
219
+ /** Empty = any recipient. */
220
+ readonly recipients: readonly string[];
221
+ readonly totalSpends: bigint;
222
+ readonly lastSpentAt: bigint;
223
+ /** Slot of `create_agent_policy`: the delegate's generation seed. */
224
+ readonly createdSlot: bigint;
225
+ }
226
+ /** Decode an `AgentPolicy` account (null when not one). */
227
+ export declare function decodeAgentPolicy(data: Uint8Array): AgentPolicyAccount | null;
228
+ /**
229
+ * What the agent may still spend of `mint` at `nowSecs` (the program's
230
+ * `roll_period` applied): null when the mint has no cap. Does NOT include
231
+ * the float / SPL allowance bound, the lock, or the policy's liveness.
232
+ */
233
+ export declare function agentPolicyRemaining(p: AgentPolicyAccount, mint: AddressLike, nowSecs: bigint): {
234
+ readonly remaining: bigint;
235
+ readonly periodEndsAt: bigint;
236
+ readonly expired: boolean;
237
+ } | null;
238
+ export {};