@x1id/resolve 0.23.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 (49) 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 +13 -0
  20. package/dist/index.js +32 -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/nsGate.d.ts +98 -0
  28. package/dist/nsGate.js +172 -0
  29. package/dist/oidc.d.ts +272 -0
  30. package/dist/oidc.js +641 -0
  31. package/dist/pay.d.ts +513 -0
  32. package/dist/pay.js +756 -0
  33. package/dist/payment.d.ts +9 -2
  34. package/dist/payment.js +9 -2
  35. package/dist/recovery.d.ts +186 -0
  36. package/dist/recovery.js +276 -0
  37. package/dist/recoveryNft.d.ts +183 -0
  38. package/dist/recoveryNft.js +291 -0
  39. package/dist/shield.d.ts +373 -0
  40. package/dist/shield.js +695 -0
  41. package/dist/subscription.d.ts +439 -0
  42. package/dist/subscription.js +642 -0
  43. package/dist/textRecords.d.ts +52 -6
  44. package/dist/textRecords.js +80 -8
  45. package/dist/types.d.ts +3 -0
  46. package/dist/x402Receipt.d.ts +246 -0
  47. package/dist/x402Receipt.js +374 -0
  48. package/package.json +18 -1
  49. package/schema/agent-manifest.json +91 -8
@@ -0,0 +1,374 @@
1
+ /**
2
+ * x402 payment receipts on chain (#8324, wired by [Pay 10] / WP 8833):
3
+ * `record_x402_receipt`, its `X402ReceiptRecorded` event and the per-handle
4
+ * `AgentPaymentStats` tally.
5
+ *
6
+ * Hand-rolled like the rest of this package — no Anchor client, no
7
+ * `@solana/web3.js`. The builder returns the transport-neutral
8
+ * {@link BuiltInstruction} (`delegate.ts` has the two-line web3.js adapter).
9
+ *
10
+ * # What a receipt proves (and what it does not)
11
+ *
12
+ * The instruction is ATTESTOR-SIGNED (`has_one = attestor` on
13
+ * `["attestor_config"]`). The program does NOT look at the payment itself: it
14
+ * does not introspect the Instructions sysvar, does not read `settled_sig`'s
15
+ * transaction, and does not check `amount` / `mint` against anything. A
16
+ * receipt therefore proves exactly one thing — "the configured attestor key
17
+ * stamped this payment" — and the attestor is trusted to have confirmed the
18
+ * settlement off chain first (`docs/x402-receipts.md`, option B). The
19
+ * `settled_sig` it carries is the audit anchor: anyone can fetch that
20
+ * transaction and check it. Never present a receipt as more than that.
21
+ *
22
+ * Both handles must be live `Handle` accounts and must differ
23
+ * (`X402SelfReceipt`, 6085). A scoped handle (`["handle", [len], label,
24
+ * name]`) needs its `["namespace", label]` account in `namespaces` (the
25
+ * program scans remaining accounts for it); a bare handle needs nothing.
26
+ *
27
+ * Cost: the attestor is the fee payer and pays the rent of each
28
+ * `AgentPaymentStats` account the first time a handle is touched (81 bytes
29
+ * each). On X1 the fee is 10 lamports per REQUESTED compute unit plus 1,500
30
+ * per signature, so always set a compute-unit limit: simulate and use
31
+ * {@link x402ReceiptCuLimitFromSimulation}, or fall back to
32
+ * {@link RECORD_X402_RECEIPT_CU_LIMIT}.
33
+ */
34
+ import { decodeBase58, decodeBase58_32, encodeBase58 } from "./base58.js";
35
+ import { sha256 } from "./sha256.js";
36
+ /** Anchor instruction discriminator: `sha256("global:record_x402_receipt")[0..8]`. */
37
+ export const RECORD_X402_RECEIPT_DISCRIMINATOR = Uint8Array.from([196, 39, 64, 88, 117, 200, 163, 232]);
38
+ /** Anchor event discriminator: `sha256("event:X402ReceiptRecorded")[0..8]`.
39
+ * An emitted event is logged as `Program data: <base64(disc ‖ borsh)>`. */
40
+ export const X402_RECEIPT_RECORDED_EVENT_DISCRIMINATOR = Uint8Array.from([37, 68, 174, 195, 241, 126, 162, 223]);
41
+ /** Anchor account discriminator: `sha256("account:AgentPaymentStats")[0..8]`. */
42
+ export const AGENT_PAYMENT_STATS_DISCRIMINATOR = Uint8Array.from([80, 161, 55, 40, 220, 73, 56, 65]);
43
+ /** Seed prefix of the stats PDA: `["x402_stats", handleAccount]`. */
44
+ export const AGENT_PAYMENT_STATS_SEED = "x402_stats";
45
+ /** `AgentPaymentStats` size: disc(8) + handle(32) + 4×u64(32) + last_at(8) + bump(1). */
46
+ export const AGENT_PAYMENT_STATS_LEN = 81;
47
+ /** `X402ReceiptRecorded` encoded size: disc(8) + payer(32) + payee(32) +
48
+ * amount(8) + mint(32) + resource_hash(32) + settled_sig(64) + timestamp(8). */
49
+ export const X402_RECEIPT_EVENT_LEN = 216;
50
+ /** `record_x402_receipt` instruction data size: disc + amount + mint +
51
+ * resource_hash + settled_sig. */
52
+ export const RECORD_X402_RECEIPT_DATA_LEN = 8 + 8 + 32 + 32 + 64;
53
+ /** `X402SelfReceipt`: payer and payee handle are the same account. */
54
+ export const X402_SELF_RECEIPT_ERROR = 6085;
55
+ /**
56
+ * Static compute-unit CEILING for a transaction carrying ONE
57
+ * `record_x402_receipt` (plus its compute-budget instruction), for callers
58
+ * that cannot simulate first. Measured in litesvm against the built program
59
+ * (programs/x1-handles/tests/x402_receipt_sdk_e2e.rs): ~40.0k CU when both
60
+ * stats accounts are created (first touch), ~28.7k CU after, with stats-PDA
61
+ * bumps 255/254. The cost is not constant: Anchor re-derives each stats PDA
62
+ * with `find_program_address` on every call, so a handle whose stats bump is
63
+ * lower costs ~1.5k CU more per step below 255. X1 charges the REQUESTED
64
+ * limit (10 lamports per CU), so the better practice — what dev-api does — is
65
+ * to simulate and request {@link x402ReceiptCuLimitFromSimulation} of the
66
+ * measured units, using this only as the fallback / upper bound.
67
+ */
68
+ export const RECORD_X402_RECEIPT_CU_LIMIT = 60_000;
69
+ /** A tight limit from a simulation's `unitsConsumed`: +10% (at least 2,000
70
+ * CU), rounded up to a thousand, never above `ceiling`. */
71
+ export function x402ReceiptCuLimitFromSimulation(unitsConsumed, ceiling = RECORD_X402_RECEIPT_CU_LIMIT * 2) {
72
+ if (!Number.isFinite(unitsConsumed) || unitsConsumed <= 0)
73
+ return Math.min(RECORD_X402_RECEIPT_CU_LIMIT, ceiling);
74
+ const padded = unitsConsumed + Math.max(2_000, Math.ceil(unitsConsumed * 0.1));
75
+ return Math.min(Math.ceil(padded / 1_000) * 1_000, ceiling);
76
+ }
77
+ const SYSTEM_PROGRAM = "11111111111111111111111111111111";
78
+ const TE = new TextEncoder();
79
+ const U64_MAX = 0xffffffffffffffffn;
80
+ function toBytes32(v, what) {
81
+ if (typeof v === "string") {
82
+ const b = decodeBase58_32(v);
83
+ if (!b)
84
+ throw new Error(`${what} is not a valid base58 address`);
85
+ return b;
86
+ }
87
+ if (v.length !== 32)
88
+ throw new Error(`${what} must be exactly 32 bytes`);
89
+ return v;
90
+ }
91
+ function toBase58(v, what) {
92
+ return encodeBase58(toBytes32(v, what));
93
+ }
94
+ /** A transaction signature as its 64 raw bytes (from base58 or bytes). */
95
+ export function x402SettledSigBytes(sig) {
96
+ if (typeof sig !== "string") {
97
+ if (sig.length !== 64)
98
+ throw new Error("settledSig must be exactly 64 bytes");
99
+ return sig;
100
+ }
101
+ const b = decodeSig(sig);
102
+ if (!b)
103
+ throw new Error("settledSig is not a base58 64-byte transaction signature");
104
+ return b;
105
+ }
106
+ function decodeSig(s) {
107
+ if (!/^[1-9A-HJ-NP-Za-km-z]{64,88}$/.test(s))
108
+ return null;
109
+ return decodeBase58(s, 64);
110
+ }
111
+ /**
112
+ * The `resource_hash` x1id stamps: sha256 of the x402 `resource` URL the
113
+ * payment bought, e.g. `https://api.x1id.io/v1/resolve`. The ENDPOINT, not the
114
+ * exact request — a receipt is public forever, and hashing the full request
115
+ * (`/v1/resolve/alice`) would let anyone brute-force what an agent looked up.
116
+ */
117
+ export function x402ResourceHash(resource) {
118
+ if (typeof resource !== "string" || resource.length === 0)
119
+ throw new Error("resource must be a non-empty string");
120
+ return sha256(TE.encode(resource));
121
+ }
122
+ /** `["x402_stats", handleAccount]` — the second seed is the 32 raw bytes of
123
+ * the Handle ACCOUNT address. */
124
+ export async function findAgentPaymentStatsPda(find, programId, handle) {
125
+ return find([TE.encode(AGENT_PAYMENT_STATS_SEED), toBytes32(handle, "handle")], toBase58(programId, "programId"));
126
+ }
127
+ /** Borsh args after the discriminator: amount u64, mint, resource_hash[32], settled_sig[64]. */
128
+ export function encodeRecordX402ReceiptArgs(a) {
129
+ if (typeof a.amount !== "bigint" || a.amount < 0n || a.amount > U64_MAX)
130
+ throw new Error("amount must be a u64 bigint");
131
+ if (!(a.resourceHash instanceof Uint8Array) || a.resourceHash.length !== 32)
132
+ throw new Error("resourceHash must be exactly 32 bytes");
133
+ const out = new Uint8Array(RECORD_X402_RECEIPT_DATA_LEN);
134
+ out.set(RECORD_X402_RECEIPT_DISCRIMINATOR, 0);
135
+ new DataView(out.buffer).setBigUint64(8, a.amount, true);
136
+ out.set(toBytes32(a.mint, "mint"), 16);
137
+ out.set(a.resourceHash, 48);
138
+ out.set(x402SettledSigBytes(a.settledSig), 80);
139
+ return out;
140
+ }
141
+ /**
142
+ * Build `record_x402_receipt`. Accounts in `RecordX402Receipt` order:
143
+ * attestor(s,w) attestor_config payer_handle payee_handle payer_stats(w)
144
+ * payee_stats(w) system_program, then any namespace accounts.
145
+ */
146
+ export function buildRecordX402ReceiptIx(p) {
147
+ const payerHandle = toBase58(p.payerHandle, "payerHandle");
148
+ const payeeHandle = toBase58(p.payeeHandle, "payeeHandle");
149
+ if (payerHandle === payeeHandle)
150
+ throw new Error("payerHandle and payeeHandle must differ (X402SelfReceipt)");
151
+ const data = encodeRecordX402ReceiptArgs(p);
152
+ const keys = [
153
+ { pubkey: toBase58(p.attestor, "attestor"), isSigner: true, isWritable: true },
154
+ { pubkey: toBase58(p.attestorConfig, "attestorConfig"), isSigner: false, isWritable: false },
155
+ { pubkey: payerHandle, isSigner: false, isWritable: false },
156
+ { pubkey: payeeHandle, isSigner: false, isWritable: false },
157
+ { pubkey: toBase58(p.payerStats, "payerStats"), isSigner: false, isWritable: true },
158
+ { pubkey: toBase58(p.payeeStats, "payeeStats"), isSigner: false, isWritable: true },
159
+ { pubkey: SYSTEM_PROGRAM, isSigner: false, isWritable: false },
160
+ ];
161
+ for (const [i, ns] of (p.namespaces ?? []).entries()) {
162
+ keys.push({ pubkey: toBase58(ns, `namespaces[${i}]`), isSigner: false, isWritable: false });
163
+ }
164
+ return { programId: toBase58(p.programId, "programId"), keys, data };
165
+ }
166
+ function eq(a, b) {
167
+ if (a.length !== b.length)
168
+ return false;
169
+ for (let i = 0; i < a.length; i++)
170
+ if (a[i] !== b[i])
171
+ return false;
172
+ return true;
173
+ }
174
+ /** Decode one event payload (the bytes of a `Program data:` line). null when
175
+ * it is not an `X402ReceiptRecorded`. */
176
+ export function decodeX402ReceiptRecorded(raw) {
177
+ if (raw.length !== X402_RECEIPT_EVENT_LEN || !eq(raw.subarray(0, 8), X402_RECEIPT_RECORDED_EVENT_DISCRIMINATOR))
178
+ return null;
179
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
180
+ return {
181
+ payerHandle: encodeBase58(raw.slice(8, 40)),
182
+ payeeHandle: encodeBase58(raw.slice(40, 72)),
183
+ amount: dv.getBigUint64(72, true),
184
+ mint: encodeBase58(raw.slice(80, 112)),
185
+ resourceHash: raw.slice(112, 144),
186
+ settledSig: encodeBase58(raw.slice(144, 208)),
187
+ timestamp: dv.getBigInt64(208, true),
188
+ };
189
+ }
190
+ /** Encode an event the way the program emits it (tests / fixtures). */
191
+ export function encodeX402ReceiptRecorded(e) {
192
+ const out = new Uint8Array(X402_RECEIPT_EVENT_LEN);
193
+ const dv = new DataView(out.buffer);
194
+ out.set(X402_RECEIPT_RECORDED_EVENT_DISCRIMINATOR, 0);
195
+ out.set(toBytes32(e.payerHandle, "payerHandle"), 8);
196
+ out.set(toBytes32(e.payeeHandle, "payeeHandle"), 40);
197
+ dv.setBigUint64(72, e.amount, true);
198
+ out.set(toBytes32(e.mint, "mint"), 80);
199
+ if (e.resourceHash.length !== 32)
200
+ throw new Error("resourceHash must be exactly 32 bytes");
201
+ out.set(e.resourceHash, 112);
202
+ out.set(x402SettledSigBytes(e.settledSig), 144);
203
+ dv.setBigInt64(208, e.timestamp, true);
204
+ return out;
205
+ }
206
+ function b64decode(s) {
207
+ try {
208
+ return Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
209
+ }
210
+ catch {
211
+ return null;
212
+ }
213
+ }
214
+ /**
215
+ * Every `X402ReceiptRecorded` among a transaction's log lines, attributed to
216
+ * `programId`'s OWN invoke frames only (a look-alike `Program data:` line
217
+ * printed by another program is ignored).
218
+ */
219
+ export function parseX402ReceiptEvents(logs, programId) {
220
+ const pid = toBase58(programId, "programId");
221
+ const stack = [];
222
+ const out = [];
223
+ for (const line of logs) {
224
+ const inv = /^Program (\S+) invoke \[\d+\]$/.exec(line);
225
+ if (inv) {
226
+ stack.push(inv[1]);
227
+ continue;
228
+ }
229
+ if (/^Program \S+ (success|failed: )/.test(line)) {
230
+ stack.pop();
231
+ continue;
232
+ }
233
+ if (line.startsWith("Program data: ") && stack[stack.length - 1] === pid) {
234
+ const raw = b64decode(line.slice("Program data: ".length).trim());
235
+ const ev = raw ? decodeX402ReceiptRecorded(raw) : null;
236
+ if (ev)
237
+ out.push(ev);
238
+ }
239
+ }
240
+ return out;
241
+ }
242
+ /** Decode an `AgentPaymentStats` account (discriminator + exact length
243
+ * checked); null for anything else. */
244
+ export function decodeAgentPaymentStats(raw) {
245
+ if (raw.length !== AGENT_PAYMENT_STATS_LEN || !eq(raw.subarray(0, 8), AGENT_PAYMENT_STATS_DISCRIMINATOR))
246
+ return null;
247
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
248
+ return {
249
+ handle: encodeBase58(raw.slice(8, 40)),
250
+ paymentsMadeCount: dv.getBigUint64(40, true),
251
+ totalPaid: dv.getBigUint64(48, true),
252
+ paymentsReceivedCount: dv.getBigUint64(56, true),
253
+ totalReceived: dv.getBigUint64(64, true),
254
+ lastAt: dv.getBigInt64(72, true),
255
+ bump: raw[80],
256
+ };
257
+ }
258
+ /** Encode an `AgentPaymentStats` account (tests / fixtures). */
259
+ export function encodeAgentPaymentStats(s) {
260
+ const out = new Uint8Array(AGENT_PAYMENT_STATS_LEN);
261
+ const dv = new DataView(out.buffer);
262
+ out.set(AGENT_PAYMENT_STATS_DISCRIMINATOR, 0);
263
+ out.set(toBytes32(s.handle, "handle"), 8);
264
+ dv.setBigUint64(40, s.paymentsMadeCount, true);
265
+ dv.setBigUint64(48, s.totalPaid, true);
266
+ dv.setBigUint64(56, s.paymentsReceivedCount, true);
267
+ dv.setBigUint64(64, s.totalReceived, true);
268
+ dv.setBigInt64(72, s.lastAt, true);
269
+ out[80] = s.bump;
270
+ return out;
271
+ }
272
+ /** Fee (lamports) of one receipt transaction on X1: 10 lamports per
273
+ * requested CU + 1,500 per signature (rent of new stats accounts excluded). */
274
+ export function x402ReceiptTxFeeLamports(cuLimit = RECORD_X402_RECEIPT_CU_LIMIT, signatures = 1) {
275
+ return cuLimit * 10 + 1_500 * signatures;
276
+ }
277
+ // ===================== dedicated receipt signer (upgrade 5) =====================
278
+ //
279
+ // `record_x402_receipt_v2` (signed by the dedicated receipt signer OR the
280
+ // attestor) and the admin's `set_receipt_signer`. Both are routed through the
281
+ // program's `fallback` (`extra_ix`) and need the registry upgrade that adds
282
+ // them (until then: `InstructionFallbackNotFound`, 101). v1
283
+ // ({@link buildRecordX402ReceiptIx}) is unchanged and stays attestor-only.
284
+ // docs/x402-receipts.md "Dedicated receipt signer (upgrade 5)".
285
+ /** Seed of the receipt-signer singleton: `["receipt_signer_config"]`. */
286
+ export const RECEIPT_SIGNER_CONFIG_SEED = "receipt_signer_config";
287
+ /** Seed of a handle's O(1) payment tally (alias of {@link AGENT_PAYMENT_STATS_SEED}). */
288
+ export const X402_STATS_SEED = AGENT_PAYMENT_STATS_SEED;
289
+ /** `sha256("global:record_x402_receipt_v2")[..8]`. */
290
+ export const RECORD_X402_RECEIPT_V2_DISCRIMINATOR = Uint8Array.from([99, 60, 56, 81, 186, 214, 82, 72]);
291
+ /** `sha256("global:set_receipt_signer")[..8]`. */
292
+ export const SET_RECEIPT_SIGNER_DISCRIMINATOR = Uint8Array.from([40, 114, 51, 32, 33, 184, 70, 80]);
293
+ /** `sha256("account:ReceiptSignerConfig")[..8]`. */
294
+ export const RECEIPT_SIGNER_CONFIG_DISCRIMINATOR = Uint8Array.from([154, 248, 63, 199, 144, 203, 157, 2]);
295
+ /** `RegistryError::NotReceiptSigner`: v2 signed by neither role. */
296
+ export const X402_NOT_RECEIPT_SIGNER_ERROR = 6157;
297
+ /** `RegistryError::X402ReceiptPayerIsSigner`: v2 with `payer == signer`
298
+ * (Sentinel run-011: the X1ID receipt key never pays). */
299
+ export const X402_RECEIPT_PAYER_IS_SIGNER_ERROR = 6232;
300
+ /** `["receipt_signer_config"]`. */
301
+ export async function findReceiptSignerConfigPda(find, programId) {
302
+ return find([TE.encode(RECEIPT_SIGNER_CONFIG_SEED)], toBase58(programId, "programId"));
303
+ }
304
+ /** `["x402_stats", handle]` (alias of {@link findAgentPaymentStatsPda}). */
305
+ export async function findX402StatsPda(find, programId, handle) {
306
+ return findAgentPaymentStatsPda(find, programId, handle);
307
+ }
308
+ /** Decode a `ReceiptSignerConfig` (`signer` base58; the default key
309
+ * `11111111111111111111111111111111` means the role is disabled). */
310
+ export function decodeReceiptSignerConfig(data) {
311
+ if (data.length < 8 + 32 + 1)
312
+ return null;
313
+ for (let i = 0; i < 8; i++)
314
+ if (data[i] !== RECEIPT_SIGNER_CONFIG_DISCRIMINATOR[i])
315
+ return null;
316
+ return { signer: encodeBase58(data.slice(8, 40)), bump: data[40] };
317
+ }
318
+ /**
319
+ * Build `record_x402_receipt_v2`: the same args as v1. Accounts
320
+ * (`RecordX402ReceiptV2`): signer(s), payer(s,w), attestor_config,
321
+ * receipt_signer_config, payer_handle, payee_handle, payer_stats(w),
322
+ * payee_stats(w), system_program, then any namespaces. Make `payer` the
323
+ * transaction fee payer so the receipt signer's key holds no XNT. Throws when
324
+ * `payer` is missing or equals `signer`.
325
+ */
326
+ export function buildRecordX402ReceiptV2Ix(p) {
327
+ if (p.receiptSignerConfig === undefined)
328
+ throw new Error("receiptSignerConfig is required for v2");
329
+ if (p.payer === undefined || p.payer === null) {
330
+ throw new Error("payer is required for v2 (the receipt signer only co-signs; X1ID pays nothing)");
331
+ }
332
+ const signer = toBase58(p.signer, "signer");
333
+ const payer = toBase58(p.payer, "payer");
334
+ if (payer === signer)
335
+ throw new Error("payer must differ from signer (X402ReceiptPayerIsSigner)");
336
+ const payerHandle = toBase58(p.payerHandle, "payerHandle");
337
+ const payeeHandle = toBase58(p.payeeHandle, "payeeHandle");
338
+ if (payerHandle === payeeHandle)
339
+ throw new Error("payerHandle and payeeHandle must differ (X402SelfReceipt)");
340
+ const data = encodeRecordX402ReceiptArgs(p);
341
+ data.set(RECORD_X402_RECEIPT_V2_DISCRIMINATOR, 0);
342
+ const keys = [
343
+ { pubkey: signer, isSigner: true, isWritable: false },
344
+ { pubkey: payer, isSigner: true, isWritable: true },
345
+ { pubkey: toBase58(p.attestorConfig, "attestorConfig"), isSigner: false, isWritable: false },
346
+ { pubkey: toBase58(p.receiptSignerConfig, "receiptSignerConfig"), isSigner: false, isWritable: false },
347
+ { pubkey: payerHandle, isSigner: false, isWritable: false },
348
+ { pubkey: payeeHandle, isSigner: false, isWritable: false },
349
+ { pubkey: toBase58(p.payerStats, "payerStats"), isSigner: false, isWritable: true },
350
+ { pubkey: toBase58(p.payeeStats, "payeeStats"), isSigner: false, isWritable: true },
351
+ { pubkey: SYSTEM_PROGRAM, isSigner: false, isWritable: false },
352
+ ];
353
+ for (const [i, ns] of (p.namespaces ?? []).entries()) {
354
+ keys.push({ pubkey: toBase58(ns, `namespaces[${i}]`), isSigner: false, isWritable: false });
355
+ }
356
+ return { programId: toBase58(p.programId, "programId"), keys, data };
357
+ }
358
+ /** `set_receipt_signer(signer)`. Accounts (`SetReceiptSigner`): admin(s,w),
359
+ * config, receipt_signer_config(w), system_program. */
360
+ export function buildSetReceiptSignerIx(p) {
361
+ const data = new Uint8Array(40);
362
+ data.set(SET_RECEIPT_SIGNER_DISCRIMINATOR, 0);
363
+ data.set(toBytes32(p.signer, "signer"), 8);
364
+ return {
365
+ programId: toBase58(p.programId, "programId"),
366
+ keys: [
367
+ { pubkey: toBase58(p.admin, "admin"), isSigner: true, isWritable: true },
368
+ { pubkey: toBase58(p.config, "config"), isSigner: false, isWritable: false },
369
+ { pubkey: toBase58(p.receiptSignerConfig, "receiptSignerConfig"), isSigner: false, isWritable: true },
370
+ { pubkey: SYSTEM_PROGRAM, isSigner: false, isWritable: false },
371
+ ],
372
+ data,
373
+ };
374
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x1id/resolve",
3
- "version": "0.23.0",
3
+ "version": "0.43.0",
4
4
  "description": "Resolve @handles and X1NS names on X1. Never silently picks between namespaces.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,6 +10,18 @@
10
10
  "types": "./dist/index.d.ts",
11
11
  "default": "./dist/index.js"
12
12
  },
13
+ "./messaging": {
14
+ "types": "./dist/messaging.d.ts",
15
+ "default": "./dist/messaging.js"
16
+ },
17
+ "./oidc": {
18
+ "types": "./dist/oidc.d.ts",
19
+ "default": "./dist/oidc.js"
20
+ },
21
+ "./login-button": {
22
+ "types": "./dist/loginButton.d.ts",
23
+ "default": "./dist/loginButton.js"
24
+ },
13
25
  "./wasm/x1_resolve_wasm.wasm": "./wasm/x1_resolve_wasm.wasm",
14
26
  "./wasm/*": "./wasm/*",
15
27
  "./package.json": "./package.json"
@@ -47,6 +59,11 @@
47
59
  "engines": {
48
60
  "node": ">=18"
49
61
  },
62
+ "dependencies": {
63
+ "@noble/ciphers": "^1.3.0",
64
+ "@noble/curves": "^1.8.0",
65
+ "@noble/hashes": "^1.4.0"
66
+ },
50
67
  "devDependencies": {
51
68
  "typescript": "^5.6.0",
52
69
  "@types/node": "^22.0.0",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://x1id.io/schema/agent-manifest.json",
4
4
  "title": "x1id agent manifest",
5
- "description": "A machine-readable description of an @handle operating as an AI agent — what it does, how to reach it, and how to pay it. Nothing here is a payment fact: payment.addresses[] is a mirror of the on-chain address Record(s) and payment.x402 is a pre-flight hint; the chain and the live 402 response always win. See docs/agent-records.md.",
5
+ "description": "A machine-readable description of an @handle operating as an AI agent — what it does, how to reach it, and how to pay it. Versions 1 and 2 are both valid; v2 adds per-capability / per-endpoint pricing, accepted payment methods and a name-bound payTo. Nothing here is a payment fact: v2's payment.payTo names an @name whose address is resolved from the chain (the W16 / name_pays_to rule), payment.addresses[] is a mirror of the on-chain address Record(s), and payment.x402 is a pre-flight hint; the chain and the live 402 response always win. See docs/agent-records.md. The SDK's validateManifest additionally checks cross-references (endpoint/capability ids), that x1id.name/handle/network match the handle being read, that payTo.name equals x1id.name, and that every priced mint is settled by a listed method.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": ["x1id"],
@@ -12,17 +12,17 @@
12
12
  "additionalProperties": false,
13
13
  "required": ["version", "name", "network", "handle"],
14
14
  "properties": {
15
- "version": { "const": 1 },
15
+ "version": { "enum": [1, 2] },
16
16
  "name": { "type": "string", "minLength": 1, "maxLength": 260, "description": "The canonical @handle name, without the @." },
17
17
  "network": { "type": "string", "enum": ["testnet", "mainnet"] },
18
- "handle": { "type": "string", "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$", "description": "The Handle PDA account address, base58 — the uniqueness anchor. A manifest served for the wrong name/handle is discarded on read." }
18
+ "handle": { "$ref": "#/$defs/Base58", "description": "The Handle PDA account address, base58 — the uniqueness anchor. A manifest served for the wrong name/handle is discarded on read." }
19
19
  }
20
20
  },
21
21
  "identity": {
22
22
  "type": "object",
23
23
  "additionalProperties": false,
24
24
  "properties": {
25
- "attestation": { "type": "string", "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$", "description": "Base58 address of a non-stale Attestation account on this handle (kind DNS or SOCIAL). See docs/agent-records.md §4 for what L1 does and does not prove." },
25
+ "attestation": { "$ref": "#/$defs/Base58", "description": "Base58 address of a non-stale Attestation account on this handle (kind DNS or SOCIAL). See docs/agent-records.md §4 for what L1 does and does not prove." },
26
26
  "description": { "type": "string", "maxLength": 2048 }
27
27
  }
28
28
  },
@@ -34,24 +34,69 @@
34
34
  "additionalProperties": false,
35
35
  "required": ["type", "url"],
36
36
  "properties": {
37
+ "id": { "$ref": "#/$defs/Id", "description": "v2: stable id referenced from capabilities.items[].endpoint." },
37
38
  "type": { "type": "string", "enum": ["x402", "mcp", "a2a", "http"] },
38
- "url": { "$ref": "#/$defs/HttpsUrl" }
39
+ "url": { "$ref": "#/$defs/HttpsUrl" },
40
+ "capabilities": { "type": "array", "maxItems": 64, "items": { "$ref": "#/$defs/Id" }, "description": "v2: capability ids served here." },
41
+ "pricing": { "$ref": "#/$defs/Pricing", "description": "v2: this endpoint's own price(s)." }
39
42
  }
40
43
  }
41
44
  },
42
45
  "capabilities": {
43
46
  "type": "object",
44
47
  "additionalProperties": false,
45
- "required": ["url"],
46
48
  "properties": {
47
49
  "schema": { "$ref": "#/$defs/HttpsUrl" },
48
- "url": { "$ref": "#/$defs/HttpsUrl" }
50
+ "url": { "$ref": "#/$defs/HttpsUrl" },
51
+ "items": {
52
+ "type": "array",
53
+ "maxItems": 64,
54
+ "description": "v2: the searchable capability list (the directory indexes items[].id).",
55
+ "items": {
56
+ "type": "object",
57
+ "additionalProperties": false,
58
+ "required": ["id"],
59
+ "properties": {
60
+ "id": { "$ref": "#/$defs/Id" },
61
+ "description": { "type": "string", "maxLength": 512 },
62
+ "endpoint": { "$ref": "#/$defs/Id" },
63
+ "pricing": { "$ref": "#/$defs/Pricing" }
64
+ }
65
+ }
66
+ }
49
67
  }
50
68
  },
51
69
  "payment": {
52
70
  "type": "object",
53
71
  "additionalProperties": false,
54
72
  "properties": {
73
+ "payTo": {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "required": ["name"],
77
+ "description": "v2: WHO gets paid — an @name (must equal x1id.name), never an address. Readers resolve the address from the chain under the W16 rule (live verified record for the method's chain, else the name's current authority on SVM chains). Required whenever anything is priced.",
78
+ "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 261 } }
79
+ },
80
+ "methods": {
81
+ "type": "array",
82
+ "minItems": 1,
83
+ "maxItems": 8,
84
+ "description": "v2: accepted payment methods. Required whenever anything is priced.",
85
+ "items": {
86
+ "type": "object",
87
+ "additionalProperties": false,
88
+ "required": ["type", "rail", "network"],
89
+ "properties": {
90
+ "id": { "$ref": "#/$defs/Id" },
91
+ "type": { "const": "x402" },
92
+ "rail": { "enum": ["x1", "cdp"], "description": "x1 = the X1-native x402 rail (self-sponsored, settled on X1); cdp = the Coinbase CDP facilitator rail." },
93
+ "network": { "type": "string", "pattern": "^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,64}$", "description": "CAIP-2. For rail x1 it must be the X1 network id of x1id.network (solana:C7ucgdDEhxLTpXHhWSZxavSVmaNTUJWw testnet, solana:4SvBP3omtvcCVWdxq1zBY5cDp4wndjsT mainnet)." },
94
+ "scheme": { "const": "exact" },
95
+ "facilitator": { "$ref": "#/$defs/HttpsUrl" },
96
+ "assets": { "type": "array", "minItems": 1, "maxItems": 16, "items": { "$ref": "#/$defs/Mint" } }
97
+ }
98
+ }
99
+ },
55
100
  "addresses": {
56
101
  "type": "array",
57
102
  "maxItems": 16,
@@ -81,11 +126,49 @@
81
126
  }
82
127
  }
83
128
  },
129
+ "allOf": [
130
+ {
131
+ "if": { "properties": { "x1id": { "properties": { "version": { "const": 1 } } } } },
132
+ "then": {
133
+ "properties": {
134
+ "capabilities": { "required": ["url"], "properties": { "items": false } },
135
+ "endpoints": { "items": { "properties": { "id": false, "capabilities": false, "pricing": false } } },
136
+ "payment": { "properties": { "payTo": false, "methods": false } }
137
+ }
138
+ }
139
+ },
140
+ {
141
+ "if": { "properties": { "x1id": { "properties": { "version": { "const": 2 } } } } },
142
+ "then": {
143
+ "properties": {
144
+ "capabilities": { "anyOf": [{ "required": ["url"] }, { "required": ["items"] }] }
145
+ }
146
+ }
147
+ }
148
+ ],
84
149
  "$defs": {
85
150
  "HttpsUrl": {
86
151
  "type": "string",
87
152
  "pattern": "^https://[^\\s@/]+(/[^\\s]*)?$",
88
153
  "maxLength": 2048
89
- }
154
+ },
155
+ "Base58": { "type": "string", "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$" },
156
+ "Id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$" },
157
+ "Mint": {
158
+ "type": "string",
159
+ "description": "\"XNT\" (native), an SPL mint (base58), or — CDP rail only — an EVM token address.",
160
+ "anyOf": [{ "const": "XNT" }, { "$ref": "#/$defs/Base58" }, { "pattern": "^0x[0-9a-fA-F]{40}$" }]
161
+ },
162
+ "Price": {
163
+ "type": "object",
164
+ "additionalProperties": false,
165
+ "required": ["amount", "mint", "unit"],
166
+ "properties": {
167
+ "amount": { "type": "string", "pattern": "^(0|[1-9][0-9]{0,19})$", "description": "Decimal string of the asset's smallest units (u64)." },
168
+ "mint": { "$ref": "#/$defs/Mint" },
169
+ "unit": { "enum": ["per-call", "per-1k-tokens", "per-1k-chars", "per-minute", "per-mb"] }
170
+ }
171
+ },
172
+ "Pricing": { "type": "array", "minItems": 1, "maxItems": 8, "items": { "$ref": "#/$defs/Price" } }
90
173
  }
91
174
  }