@relai-fi/x402 0.5.19 → 0.5.21

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.
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/crossmint.ts
21
+ var crossmint_exports = {};
22
+ __export(crossmint_exports, {
23
+ createCrossmintX402Fetch: () => createCrossmintX402Fetch
24
+ });
25
+ module.exports = __toCommonJS(crossmint_exports);
26
+ var import_web3 = require("@solana/web3.js");
27
+ var import_spl_token = require("@solana/spl-token");
28
+ var DEFAULT_API_BASE = "https://www.crossmint.com/api/2025-06-09";
29
+ function toBase58(bytes) {
30
+ const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
31
+ const digits = [0];
32
+ for (const byte of bytes) {
33
+ let carry = byte;
34
+ for (let j = 0; j < digits.length; j++) {
35
+ carry += digits[j] << 8;
36
+ digits[j] = carry % 58;
37
+ carry = carry / 58 | 0;
38
+ }
39
+ while (carry > 0) {
40
+ digits.push(carry % 58);
41
+ carry = carry / 58 | 0;
42
+ }
43
+ }
44
+ let str = "";
45
+ for (const byte of bytes) {
46
+ if (byte === 0) str += ALPHABET[0];
47
+ else break;
48
+ }
49
+ for (let i = digits.length - 1; i >= 0; i--) {
50
+ str += ALPHABET[digits[i]];
51
+ }
52
+ return str;
53
+ }
54
+ function extractSignature(onChainTx) {
55
+ if (!onChainTx) return null;
56
+ if (onChainTx.length <= 100) return onChainTx;
57
+ try {
58
+ const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
59
+ const BASE_MAP = new Uint8Array(256).fill(255);
60
+ for (let i = 0; i < ALPHABET.length; i++) BASE_MAP[ALPHABET.charCodeAt(i)] = i;
61
+ const bytes = [0];
62
+ for (const ch of onChainTx) {
63
+ const carry_init = BASE_MAP[ch.charCodeAt(0)];
64
+ if (carry_init === 255) return null;
65
+ let carry = carry_init;
66
+ for (let j = 0; j < bytes.length; j++) {
67
+ carry += bytes[j] * 58;
68
+ bytes[j] = carry & 255;
69
+ carry >>= 8;
70
+ }
71
+ while (carry > 0) {
72
+ bytes.push(carry & 255);
73
+ carry >>= 8;
74
+ }
75
+ }
76
+ for (const ch of onChainTx) {
77
+ if (ch === ALPHABET[0]) bytes.push(0);
78
+ else break;
79
+ }
80
+ const decoded = new Uint8Array(bytes.reverse());
81
+ const vtx = import_web3.VersionedTransaction.deserialize(decoded);
82
+ if (vtx.signatures?.[0]) return toBase58(vtx.signatures[0]);
83
+ } catch {
84
+ }
85
+ return null;
86
+ }
87
+ function createCrossmintX402Fetch(config) {
88
+ const { apiKey, wallet, connection } = config;
89
+ const apiBase = config.crossmintApiBase || DEFAULT_API_BASE;
90
+ const maxPolls = config.maxPollAttempts ?? 30;
91
+ const pollMs = config.pollIntervalMs ?? 2e3;
92
+ const userPubkey = new import_web3.PublicKey(wallet);
93
+ return async function fetch402(url, init) {
94
+ const firstResp = await fetch(url, {
95
+ ...init,
96
+ headers: { Accept: "application/json", ...init?.headers }
97
+ });
98
+ if (firstResp.status !== 402) return firstResp;
99
+ const requirements = await firstResp.json();
100
+ const accept = requirements.accepts?.[0];
101
+ if (!accept) throw new Error("[x402/crossmint] No payment requirements in 402 response");
102
+ const mintPubkey = new import_web3.PublicKey(accept.asset);
103
+ const merchantPubkey = new import_web3.PublicKey(accept.payTo);
104
+ const mintAccountInfo = await connection.getAccountInfo(mintPubkey);
105
+ const programId = mintAccountInfo?.owner.equals(import_spl_token.TOKEN_2022_PROGRAM_ID) ? import_spl_token.TOKEN_2022_PROGRAM_ID : import_spl_token.TOKEN_PROGRAM_ID;
106
+ const mintInfo = await (0, import_spl_token.getMint)(connection, mintPubkey, "confirmed", programId);
107
+ const amount = BigInt(accept.amount);
108
+ const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(mintPubkey, userPubkey, true, programId);
109
+ const destAta = await (0, import_spl_token.getAssociatedTokenAddress)(mintPubkey, merchantPubkey, true, programId);
110
+ const ix = (0, import_spl_token.createTransferCheckedInstruction)(
111
+ sourceAta,
112
+ mintPubkey,
113
+ destAta,
114
+ userPubkey,
115
+ amount,
116
+ mintInfo.decimals,
117
+ [],
118
+ programId
119
+ );
120
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
121
+ const msg = new import_web3.TransactionMessage({
122
+ payerKey: userPubkey,
123
+ recentBlockhash: blockhash,
124
+ instructions: [ix]
125
+ }).compileToV0Message();
126
+ const unsignedTx = new import_web3.VersionedTransaction(msg);
127
+ const serializedBase58 = toBase58(unsignedTx.serialize());
128
+ const txResp = await fetch(
129
+ `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions`,
130
+ {
131
+ method: "POST",
132
+ headers: { "Content-Type": "application/json", "X-API-KEY": apiKey },
133
+ body: JSON.stringify({ params: { transaction: serializedBase58 } })
134
+ }
135
+ );
136
+ const txData = await txResp.json();
137
+ if (!txResp.ok || !txData.id) {
138
+ throw new Error(`[x402/crossmint] Crossmint API error: ${JSON.stringify(txData)}`);
139
+ }
140
+ let sig = txData.onChain?.txId || extractSignature(txData.onChain?.transaction) || null;
141
+ for (let i = 0; i < maxPolls && !sig; i++) {
142
+ await new Promise((r) => setTimeout(r, pollMs));
143
+ const poll = await fetch(
144
+ `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions/${txData.id}`,
145
+ { headers: { "X-API-KEY": apiKey } }
146
+ );
147
+ const p = await poll.json();
148
+ if (p.status === "failed") {
149
+ throw new Error(`[x402/crossmint] Crossmint tx failed: ${p.error?.message || "unknown"}`);
150
+ }
151
+ sig = p.onChain?.txId || extractSignature(p.onChain?.transaction) || null;
152
+ }
153
+ if (!sig) {
154
+ throw new Error("[x402/crossmint] Timed out waiting for Crossmint tx confirmation");
155
+ }
156
+ const payload = {
157
+ x402Version: 2,
158
+ scheme: "exact",
159
+ network: accept.network,
160
+ payload: {
161
+ transaction: Buffer.from(unsignedTx.serialize()).toString("base64"),
162
+ txId: sig
163
+ },
164
+ accepted: {
165
+ scheme: accept.scheme,
166
+ network: accept.network,
167
+ amount: accept.amount,
168
+ asset: accept.asset,
169
+ payTo: accept.payTo
170
+ }
171
+ };
172
+ const xPayment = Buffer.from(JSON.stringify(payload)).toString("base64");
173
+ return fetch(url, {
174
+ ...init,
175
+ headers: { Accept: "application/json", "X-PAYMENT": xPayment, ...init?.headers }
176
+ });
177
+ };
178
+ }
179
+ // Annotate the CommonJS export names for ESM import in node:
180
+ 0 && (module.exports = {
181
+ createCrossmintX402Fetch
182
+ });
183
+ //# sourceMappingURL=crossmint.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/crossmint.ts"],"sourcesContent":["/**\n * Crossmint smart wallet integration for RelAI x402.\n *\n * Auto-handles 402 Payment Required responses using a Crossmint\n * API-key smart wallet on Solana. Zero private keys needed —\n * Crossmint signs and broadcasts, RelAI facilitator verifies on-chain.\n *\n * @example\n * ```ts\n * import { createCrossmintX402Fetch } from \"@relai-fi/x402/crossmint\";\n * import { Connection } from \"@solana/web3.js\";\n *\n * const fetch402 = createCrossmintX402Fetch({\n * apiKey: process.env.CROSSMINT_API_KEY!,\n * wallet: process.env.CROSSMINT_WALLET!,\n * connection: new Connection(process.env.RPC_URL!),\n * });\n *\n * const resp = await fetch402(\"https://api.example.com/protected\");\n * console.log(await resp.json()); // paid content\n * ```\n *\n * @module\n */\nimport {\n Connection,\n PublicKey,\n VersionedTransaction,\n TransactionMessage,\n} from \"@solana/web3.js\";\nimport {\n getAssociatedTokenAddress,\n createTransferCheckedInstruction,\n getMint,\n TOKEN_PROGRAM_ID,\n TOKEN_2022_PROGRAM_ID,\n} from \"@solana/spl-token\";\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface CrossmintX402Config {\n /** Crossmint server-side API key (`sk_production_...` or `sk_staging_...`) */\n apiKey: string;\n\n /** Crossmint smart wallet address (Solana public key) */\n wallet: string;\n\n /** Solana RPC connection */\n connection: Connection;\n\n /** Override Crossmint API base URL (default: `https://www.crossmint.com/api/2025-06-09`) */\n crossmintApiBase?: string;\n\n /** Max polling attempts for tx confirmation (default: 30) */\n maxPollAttempts?: number;\n\n /** Polling interval in ms (default: 2000) */\n pollIntervalMs?: number;\n}\n\n// ── Internals ───────────────────────────────────────────────────────\n\nconst DEFAULT_API_BASE = \"https://www.crossmint.com/api/2025-06-09\";\n\n/** Encode bytes to base58 without external dependency. */\nfunction toBase58(bytes: Uint8Array): string {\n const ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n const digits = [0];\n for (const byte of bytes) {\n let carry = byte;\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n let str = \"\";\n for (const byte of bytes) {\n if (byte === 0) str += ALPHABET[0];\n else break;\n }\n for (let i = digits.length - 1; i >= 0; i--) {\n str += ALPHABET[digits[i]];\n }\n return str;\n}\n\n/** Extract Solana signature from Crossmint's full serialized tx (base58). */\nfunction extractSignature(onChainTx: string): string | null {\n if (!onChainTx) return null;\n if (onChainTx.length <= 100) return onChainTx; // Already a bare signature\n try {\n // Decode base58 → deserialize VersionedTransaction → first signature\n const ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n const BASE_MAP = new Uint8Array(256).fill(255);\n for (let i = 0; i < ALPHABET.length; i++) BASE_MAP[ALPHABET.charCodeAt(i)] = i;\n const bytes: number[] = [0];\n for (const ch of onChainTx) {\n const carry_init = BASE_MAP[ch.charCodeAt(0)];\n if (carry_init === 255) return null;\n let carry = carry_init;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n for (const ch of onChainTx) {\n if (ch === ALPHABET[0]) bytes.push(0);\n else break;\n }\n const decoded = new Uint8Array(bytes.reverse());\n const vtx = VersionedTransaction.deserialize(decoded);\n if (vtx.signatures?.[0]) return toBase58(vtx.signatures[0]);\n } catch {\n // Not a valid serialized tx\n }\n return null;\n}\n\n// ── Public API ──────────────────────────────────────────────────────\n\n/**\n * Create a fetch wrapper that auto-handles x402 `402 Payment Required`\n * responses using a Crossmint smart wallet on Solana.\n *\n * The returned function has the same signature as `fetch()`.\n * On a 402 response it will:\n * 1. Parse payment requirements\n * 2. Build a Solana SPL transfer instruction\n * 3. Submit to Crossmint API (which signs + broadcasts)\n * 4. Poll for on-chain confirmation\n * 5. Retry the original request with an `X-PAYMENT` header\n */\nexport function createCrossmintX402Fetch(config: CrossmintX402Config) {\n const { apiKey, wallet, connection } = config;\n const apiBase = config.crossmintApiBase || DEFAULT_API_BASE;\n const maxPolls = config.maxPollAttempts ?? 30;\n const pollMs = config.pollIntervalMs ?? 2000;\n const userPubkey = new PublicKey(wallet);\n\n return async function fetch402(\n url: string,\n init?: RequestInit,\n ): Promise<Response> {\n // 1. Initial request\n const firstResp = await fetch(url, {\n ...init,\n headers: { Accept: \"application/json\", ...init?.headers },\n });\n if (firstResp.status !== 402) return firstResp;\n\n // 2. Parse payment requirements\n const requirements = (await firstResp.json()) as any;\n const accept = requirements.accepts?.[0];\n if (!accept) throw new Error(\"[x402/crossmint] No payment requirements in 402 response\");\n\n // 3. Build SPL transfer instruction\n const mintPubkey = new PublicKey(accept.asset);\n const merchantPubkey = new PublicKey(accept.payTo);\n const mintAccountInfo = await connection.getAccountInfo(mintPubkey);\n const programId = mintAccountInfo?.owner.equals(TOKEN_2022_PROGRAM_ID)\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n const mintInfo = await getMint(connection, mintPubkey, \"confirmed\", programId);\n const amount = BigInt(accept.amount);\n\n const sourceAta = await getAssociatedTokenAddress(mintPubkey, userPubkey, true, programId);\n const destAta = await getAssociatedTokenAddress(mintPubkey, merchantPubkey, true, programId);\n\n const ix = createTransferCheckedInstruction(\n sourceAta, mintPubkey, destAta, userPubkey,\n amount, mintInfo.decimals, [], programId,\n );\n\n const { blockhash } = await connection.getLatestBlockhash(\"confirmed\");\n const msg = new TransactionMessage({\n payerKey: userPubkey,\n recentBlockhash: blockhash,\n instructions: [ix],\n }).compileToV0Message();\n\n const unsignedTx = new VersionedTransaction(msg);\n const serializedBase58 = toBase58(unsignedTx.serialize());\n\n // 4. Send to Crossmint (signs + broadcasts)\n const txResp = await fetch(\n `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-API-KEY\": apiKey },\n body: JSON.stringify({ params: { transaction: serializedBase58 } }),\n },\n );\n const txData = (await txResp.json()) as any;\n if (!txResp.ok || !txData.id) {\n throw new Error(`[x402/crossmint] Crossmint API error: ${JSON.stringify(txData)}`);\n }\n\n // 5. Poll for on-chain signature\n let sig: string | null =\n txData.onChain?.txId || extractSignature(txData.onChain?.transaction) || null;\n\n for (let i = 0; i < maxPolls && !sig; i++) {\n await new Promise((r) => setTimeout(r, pollMs));\n const poll = await fetch(\n `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions/${txData.id}`,\n { headers: { \"X-API-KEY\": apiKey } },\n );\n const p = (await poll.json()) as any;\n if (p.status === \"failed\") {\n throw new Error(`[x402/crossmint] Crossmint tx failed: ${p.error?.message || \"unknown\"}`);\n }\n sig = p.onChain?.txId || extractSignature(p.onChain?.transaction) || null;\n }\n if (!sig) {\n throw new Error(\"[x402/crossmint] Timed out waiting for Crossmint tx confirmation\");\n }\n\n // 6. Build X-PAYMENT header with pre-broadcast txId\n const payload = {\n x402Version: 2,\n scheme: \"exact\",\n network: accept.network,\n payload: {\n transaction: Buffer.from(unsignedTx.serialize()).toString(\"base64\"),\n txId: sig,\n },\n accepted: {\n scheme: accept.scheme,\n network: accept.network,\n amount: accept.amount,\n asset: accept.asset,\n payTo: accept.payTo,\n },\n };\n const xPayment = Buffer.from(JSON.stringify(payload)).toString(\"base64\");\n\n // 7. Retry with payment\n return fetch(url, {\n ...init,\n headers: { Accept: \"application/json\", \"X-PAYMENT\": xPayment, ...init?.headers },\n });\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,56 @@
1
+ import { Connection } from '@solana/web3.js';
2
+
3
+ /**
4
+ * Crossmint smart wallet integration for RelAI x402.
5
+ *
6
+ * Auto-handles 402 Payment Required responses using a Crossmint
7
+ * API-key smart wallet on Solana. Zero private keys needed —
8
+ * Crossmint signs and broadcasts, RelAI facilitator verifies on-chain.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { createCrossmintX402Fetch } from "@relai-fi/x402/crossmint";
13
+ * import { Connection } from "@solana/web3.js";
14
+ *
15
+ * const fetch402 = createCrossmintX402Fetch({
16
+ * apiKey: process.env.CROSSMINT_API_KEY!,
17
+ * wallet: process.env.CROSSMINT_WALLET!,
18
+ * connection: new Connection(process.env.RPC_URL!),
19
+ * });
20
+ *
21
+ * const resp = await fetch402("https://api.example.com/protected");
22
+ * console.log(await resp.json()); // paid content
23
+ * ```
24
+ *
25
+ * @module
26
+ */
27
+
28
+ interface CrossmintX402Config {
29
+ /** Crossmint server-side API key (`sk_production_...` or `sk_staging_...`) */
30
+ apiKey: string;
31
+ /** Crossmint smart wallet address (Solana public key) */
32
+ wallet: string;
33
+ /** Solana RPC connection */
34
+ connection: Connection;
35
+ /** Override Crossmint API base URL (default: `https://www.crossmint.com/api/2025-06-09`) */
36
+ crossmintApiBase?: string;
37
+ /** Max polling attempts for tx confirmation (default: 30) */
38
+ maxPollAttempts?: number;
39
+ /** Polling interval in ms (default: 2000) */
40
+ pollIntervalMs?: number;
41
+ }
42
+ /**
43
+ * Create a fetch wrapper that auto-handles x402 `402 Payment Required`
44
+ * responses using a Crossmint smart wallet on Solana.
45
+ *
46
+ * The returned function has the same signature as `fetch()`.
47
+ * On a 402 response it will:
48
+ * 1. Parse payment requirements
49
+ * 2. Build a Solana SPL transfer instruction
50
+ * 3. Submit to Crossmint API (which signs + broadcasts)
51
+ * 4. Poll for on-chain confirmation
52
+ * 5. Retry the original request with an `X-PAYMENT` header
53
+ */
54
+ declare function createCrossmintX402Fetch(config: CrossmintX402Config): (url: string, init?: RequestInit) => Promise<Response>;
55
+
56
+ export { type CrossmintX402Config, createCrossmintX402Fetch };
@@ -0,0 +1,56 @@
1
+ import { Connection } from '@solana/web3.js';
2
+
3
+ /**
4
+ * Crossmint smart wallet integration for RelAI x402.
5
+ *
6
+ * Auto-handles 402 Payment Required responses using a Crossmint
7
+ * API-key smart wallet on Solana. Zero private keys needed —
8
+ * Crossmint signs and broadcasts, RelAI facilitator verifies on-chain.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { createCrossmintX402Fetch } from "@relai-fi/x402/crossmint";
13
+ * import { Connection } from "@solana/web3.js";
14
+ *
15
+ * const fetch402 = createCrossmintX402Fetch({
16
+ * apiKey: process.env.CROSSMINT_API_KEY!,
17
+ * wallet: process.env.CROSSMINT_WALLET!,
18
+ * connection: new Connection(process.env.RPC_URL!),
19
+ * });
20
+ *
21
+ * const resp = await fetch402("https://api.example.com/protected");
22
+ * console.log(await resp.json()); // paid content
23
+ * ```
24
+ *
25
+ * @module
26
+ */
27
+
28
+ interface CrossmintX402Config {
29
+ /** Crossmint server-side API key (`sk_production_...` or `sk_staging_...`) */
30
+ apiKey: string;
31
+ /** Crossmint smart wallet address (Solana public key) */
32
+ wallet: string;
33
+ /** Solana RPC connection */
34
+ connection: Connection;
35
+ /** Override Crossmint API base URL (default: `https://www.crossmint.com/api/2025-06-09`) */
36
+ crossmintApiBase?: string;
37
+ /** Max polling attempts for tx confirmation (default: 30) */
38
+ maxPollAttempts?: number;
39
+ /** Polling interval in ms (default: 2000) */
40
+ pollIntervalMs?: number;
41
+ }
42
+ /**
43
+ * Create a fetch wrapper that auto-handles x402 `402 Payment Required`
44
+ * responses using a Crossmint smart wallet on Solana.
45
+ *
46
+ * The returned function has the same signature as `fetch()`.
47
+ * On a 402 response it will:
48
+ * 1. Parse payment requirements
49
+ * 2. Build a Solana SPL transfer instruction
50
+ * 3. Submit to Crossmint API (which signs + broadcasts)
51
+ * 4. Poll for on-chain confirmation
52
+ * 5. Retry the original request with an `X-PAYMENT` header
53
+ */
54
+ declare function createCrossmintX402Fetch(config: CrossmintX402Config): (url: string, init?: RequestInit) => Promise<Response>;
55
+
56
+ export { type CrossmintX402Config, createCrossmintX402Fetch };
@@ -0,0 +1,168 @@
1
+ // src/crossmint.ts
2
+ import {
3
+ PublicKey,
4
+ VersionedTransaction,
5
+ TransactionMessage
6
+ } from "@solana/web3.js";
7
+ import {
8
+ getAssociatedTokenAddress,
9
+ createTransferCheckedInstruction,
10
+ getMint,
11
+ TOKEN_PROGRAM_ID,
12
+ TOKEN_2022_PROGRAM_ID
13
+ } from "@solana/spl-token";
14
+ var DEFAULT_API_BASE = "https://www.crossmint.com/api/2025-06-09";
15
+ function toBase58(bytes) {
16
+ const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
17
+ const digits = [0];
18
+ for (const byte of bytes) {
19
+ let carry = byte;
20
+ for (let j = 0; j < digits.length; j++) {
21
+ carry += digits[j] << 8;
22
+ digits[j] = carry % 58;
23
+ carry = carry / 58 | 0;
24
+ }
25
+ while (carry > 0) {
26
+ digits.push(carry % 58);
27
+ carry = carry / 58 | 0;
28
+ }
29
+ }
30
+ let str = "";
31
+ for (const byte of bytes) {
32
+ if (byte === 0) str += ALPHABET[0];
33
+ else break;
34
+ }
35
+ for (let i = digits.length - 1; i >= 0; i--) {
36
+ str += ALPHABET[digits[i]];
37
+ }
38
+ return str;
39
+ }
40
+ function extractSignature(onChainTx) {
41
+ if (!onChainTx) return null;
42
+ if (onChainTx.length <= 100) return onChainTx;
43
+ try {
44
+ const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
45
+ const BASE_MAP = new Uint8Array(256).fill(255);
46
+ for (let i = 0; i < ALPHABET.length; i++) BASE_MAP[ALPHABET.charCodeAt(i)] = i;
47
+ const bytes = [0];
48
+ for (const ch of onChainTx) {
49
+ const carry_init = BASE_MAP[ch.charCodeAt(0)];
50
+ if (carry_init === 255) return null;
51
+ let carry = carry_init;
52
+ for (let j = 0; j < bytes.length; j++) {
53
+ carry += bytes[j] * 58;
54
+ bytes[j] = carry & 255;
55
+ carry >>= 8;
56
+ }
57
+ while (carry > 0) {
58
+ bytes.push(carry & 255);
59
+ carry >>= 8;
60
+ }
61
+ }
62
+ for (const ch of onChainTx) {
63
+ if (ch === ALPHABET[0]) bytes.push(0);
64
+ else break;
65
+ }
66
+ const decoded = new Uint8Array(bytes.reverse());
67
+ const vtx = VersionedTransaction.deserialize(decoded);
68
+ if (vtx.signatures?.[0]) return toBase58(vtx.signatures[0]);
69
+ } catch {
70
+ }
71
+ return null;
72
+ }
73
+ function createCrossmintX402Fetch(config) {
74
+ const { apiKey, wallet, connection } = config;
75
+ const apiBase = config.crossmintApiBase || DEFAULT_API_BASE;
76
+ const maxPolls = config.maxPollAttempts ?? 30;
77
+ const pollMs = config.pollIntervalMs ?? 2e3;
78
+ const userPubkey = new PublicKey(wallet);
79
+ return async function fetch402(url, init) {
80
+ const firstResp = await fetch(url, {
81
+ ...init,
82
+ headers: { Accept: "application/json", ...init?.headers }
83
+ });
84
+ if (firstResp.status !== 402) return firstResp;
85
+ const requirements = await firstResp.json();
86
+ const accept = requirements.accepts?.[0];
87
+ if (!accept) throw new Error("[x402/crossmint] No payment requirements in 402 response");
88
+ const mintPubkey = new PublicKey(accept.asset);
89
+ const merchantPubkey = new PublicKey(accept.payTo);
90
+ const mintAccountInfo = await connection.getAccountInfo(mintPubkey);
91
+ const programId = mintAccountInfo?.owner.equals(TOKEN_2022_PROGRAM_ID) ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID;
92
+ const mintInfo = await getMint(connection, mintPubkey, "confirmed", programId);
93
+ const amount = BigInt(accept.amount);
94
+ const sourceAta = await getAssociatedTokenAddress(mintPubkey, userPubkey, true, programId);
95
+ const destAta = await getAssociatedTokenAddress(mintPubkey, merchantPubkey, true, programId);
96
+ const ix = createTransferCheckedInstruction(
97
+ sourceAta,
98
+ mintPubkey,
99
+ destAta,
100
+ userPubkey,
101
+ amount,
102
+ mintInfo.decimals,
103
+ [],
104
+ programId
105
+ );
106
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
107
+ const msg = new TransactionMessage({
108
+ payerKey: userPubkey,
109
+ recentBlockhash: blockhash,
110
+ instructions: [ix]
111
+ }).compileToV0Message();
112
+ const unsignedTx = new VersionedTransaction(msg);
113
+ const serializedBase58 = toBase58(unsignedTx.serialize());
114
+ const txResp = await fetch(
115
+ `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions`,
116
+ {
117
+ method: "POST",
118
+ headers: { "Content-Type": "application/json", "X-API-KEY": apiKey },
119
+ body: JSON.stringify({ params: { transaction: serializedBase58 } })
120
+ }
121
+ );
122
+ const txData = await txResp.json();
123
+ if (!txResp.ok || !txData.id) {
124
+ throw new Error(`[x402/crossmint] Crossmint API error: ${JSON.stringify(txData)}`);
125
+ }
126
+ let sig = txData.onChain?.txId || extractSignature(txData.onChain?.transaction) || null;
127
+ for (let i = 0; i < maxPolls && !sig; i++) {
128
+ await new Promise((r) => setTimeout(r, pollMs));
129
+ const poll = await fetch(
130
+ `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions/${txData.id}`,
131
+ { headers: { "X-API-KEY": apiKey } }
132
+ );
133
+ const p = await poll.json();
134
+ if (p.status === "failed") {
135
+ throw new Error(`[x402/crossmint] Crossmint tx failed: ${p.error?.message || "unknown"}`);
136
+ }
137
+ sig = p.onChain?.txId || extractSignature(p.onChain?.transaction) || null;
138
+ }
139
+ if (!sig) {
140
+ throw new Error("[x402/crossmint] Timed out waiting for Crossmint tx confirmation");
141
+ }
142
+ const payload = {
143
+ x402Version: 2,
144
+ scheme: "exact",
145
+ network: accept.network,
146
+ payload: {
147
+ transaction: Buffer.from(unsignedTx.serialize()).toString("base64"),
148
+ txId: sig
149
+ },
150
+ accepted: {
151
+ scheme: accept.scheme,
152
+ network: accept.network,
153
+ amount: accept.amount,
154
+ asset: accept.asset,
155
+ payTo: accept.payTo
156
+ }
157
+ };
158
+ const xPayment = Buffer.from(JSON.stringify(payload)).toString("base64");
159
+ return fetch(url, {
160
+ ...init,
161
+ headers: { Accept: "application/json", "X-PAYMENT": xPayment, ...init?.headers }
162
+ });
163
+ };
164
+ }
165
+ export {
166
+ createCrossmintX402Fetch
167
+ };
168
+ //# sourceMappingURL=crossmint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/crossmint.ts"],"sourcesContent":["/**\n * Crossmint smart wallet integration for RelAI x402.\n *\n * Auto-handles 402 Payment Required responses using a Crossmint\n * API-key smart wallet on Solana. Zero private keys needed —\n * Crossmint signs and broadcasts, RelAI facilitator verifies on-chain.\n *\n * @example\n * ```ts\n * import { createCrossmintX402Fetch } from \"@relai-fi/x402/crossmint\";\n * import { Connection } from \"@solana/web3.js\";\n *\n * const fetch402 = createCrossmintX402Fetch({\n * apiKey: process.env.CROSSMINT_API_KEY!,\n * wallet: process.env.CROSSMINT_WALLET!,\n * connection: new Connection(process.env.RPC_URL!),\n * });\n *\n * const resp = await fetch402(\"https://api.example.com/protected\");\n * console.log(await resp.json()); // paid content\n * ```\n *\n * @module\n */\nimport {\n Connection,\n PublicKey,\n VersionedTransaction,\n TransactionMessage,\n} from \"@solana/web3.js\";\nimport {\n getAssociatedTokenAddress,\n createTransferCheckedInstruction,\n getMint,\n TOKEN_PROGRAM_ID,\n TOKEN_2022_PROGRAM_ID,\n} from \"@solana/spl-token\";\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface CrossmintX402Config {\n /** Crossmint server-side API key (`sk_production_...` or `sk_staging_...`) */\n apiKey: string;\n\n /** Crossmint smart wallet address (Solana public key) */\n wallet: string;\n\n /** Solana RPC connection */\n connection: Connection;\n\n /** Override Crossmint API base URL (default: `https://www.crossmint.com/api/2025-06-09`) */\n crossmintApiBase?: string;\n\n /** Max polling attempts for tx confirmation (default: 30) */\n maxPollAttempts?: number;\n\n /** Polling interval in ms (default: 2000) */\n pollIntervalMs?: number;\n}\n\n// ── Internals ───────────────────────────────────────────────────────\n\nconst DEFAULT_API_BASE = \"https://www.crossmint.com/api/2025-06-09\";\n\n/** Encode bytes to base58 without external dependency. */\nfunction toBase58(bytes: Uint8Array): string {\n const ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n const digits = [0];\n for (const byte of bytes) {\n let carry = byte;\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n let str = \"\";\n for (const byte of bytes) {\n if (byte === 0) str += ALPHABET[0];\n else break;\n }\n for (let i = digits.length - 1; i >= 0; i--) {\n str += ALPHABET[digits[i]];\n }\n return str;\n}\n\n/** Extract Solana signature from Crossmint's full serialized tx (base58). */\nfunction extractSignature(onChainTx: string): string | null {\n if (!onChainTx) return null;\n if (onChainTx.length <= 100) return onChainTx; // Already a bare signature\n try {\n // Decode base58 → deserialize VersionedTransaction → first signature\n const ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n const BASE_MAP = new Uint8Array(256).fill(255);\n for (let i = 0; i < ALPHABET.length; i++) BASE_MAP[ALPHABET.charCodeAt(i)] = i;\n const bytes: number[] = [0];\n for (const ch of onChainTx) {\n const carry_init = BASE_MAP[ch.charCodeAt(0)];\n if (carry_init === 255) return null;\n let carry = carry_init;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n for (const ch of onChainTx) {\n if (ch === ALPHABET[0]) bytes.push(0);\n else break;\n }\n const decoded = new Uint8Array(bytes.reverse());\n const vtx = VersionedTransaction.deserialize(decoded);\n if (vtx.signatures?.[0]) return toBase58(vtx.signatures[0]);\n } catch {\n // Not a valid serialized tx\n }\n return null;\n}\n\n// ── Public API ──────────────────────────────────────────────────────\n\n/**\n * Create a fetch wrapper that auto-handles x402 `402 Payment Required`\n * responses using a Crossmint smart wallet on Solana.\n *\n * The returned function has the same signature as `fetch()`.\n * On a 402 response it will:\n * 1. Parse payment requirements\n * 2. Build a Solana SPL transfer instruction\n * 3. Submit to Crossmint API (which signs + broadcasts)\n * 4. Poll for on-chain confirmation\n * 5. Retry the original request with an `X-PAYMENT` header\n */\nexport function createCrossmintX402Fetch(config: CrossmintX402Config) {\n const { apiKey, wallet, connection } = config;\n const apiBase = config.crossmintApiBase || DEFAULT_API_BASE;\n const maxPolls = config.maxPollAttempts ?? 30;\n const pollMs = config.pollIntervalMs ?? 2000;\n const userPubkey = new PublicKey(wallet);\n\n return async function fetch402(\n url: string,\n init?: RequestInit,\n ): Promise<Response> {\n // 1. Initial request\n const firstResp = await fetch(url, {\n ...init,\n headers: { Accept: \"application/json\", ...init?.headers },\n });\n if (firstResp.status !== 402) return firstResp;\n\n // 2. Parse payment requirements\n const requirements = (await firstResp.json()) as any;\n const accept = requirements.accepts?.[0];\n if (!accept) throw new Error(\"[x402/crossmint] No payment requirements in 402 response\");\n\n // 3. Build SPL transfer instruction\n const mintPubkey = new PublicKey(accept.asset);\n const merchantPubkey = new PublicKey(accept.payTo);\n const mintAccountInfo = await connection.getAccountInfo(mintPubkey);\n const programId = mintAccountInfo?.owner.equals(TOKEN_2022_PROGRAM_ID)\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n const mintInfo = await getMint(connection, mintPubkey, \"confirmed\", programId);\n const amount = BigInt(accept.amount);\n\n const sourceAta = await getAssociatedTokenAddress(mintPubkey, userPubkey, true, programId);\n const destAta = await getAssociatedTokenAddress(mintPubkey, merchantPubkey, true, programId);\n\n const ix = createTransferCheckedInstruction(\n sourceAta, mintPubkey, destAta, userPubkey,\n amount, mintInfo.decimals, [], programId,\n );\n\n const { blockhash } = await connection.getLatestBlockhash(\"confirmed\");\n const msg = new TransactionMessage({\n payerKey: userPubkey,\n recentBlockhash: blockhash,\n instructions: [ix],\n }).compileToV0Message();\n\n const unsignedTx = new VersionedTransaction(msg);\n const serializedBase58 = toBase58(unsignedTx.serialize());\n\n // 4. Send to Crossmint (signs + broadcasts)\n const txResp = await fetch(\n `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-API-KEY\": apiKey },\n body: JSON.stringify({ params: { transaction: serializedBase58 } }),\n },\n );\n const txData = (await txResp.json()) as any;\n if (!txResp.ok || !txData.id) {\n throw new Error(`[x402/crossmint] Crossmint API error: ${JSON.stringify(txData)}`);\n }\n\n // 5. Poll for on-chain signature\n let sig: string | null =\n txData.onChain?.txId || extractSignature(txData.onChain?.transaction) || null;\n\n for (let i = 0; i < maxPolls && !sig; i++) {\n await new Promise((r) => setTimeout(r, pollMs));\n const poll = await fetch(\n `${apiBase}/wallets/${encodeURIComponent(wallet)}/transactions/${txData.id}`,\n { headers: { \"X-API-KEY\": apiKey } },\n );\n const p = (await poll.json()) as any;\n if (p.status === \"failed\") {\n throw new Error(`[x402/crossmint] Crossmint tx failed: ${p.error?.message || \"unknown\"}`);\n }\n sig = p.onChain?.txId || extractSignature(p.onChain?.transaction) || null;\n }\n if (!sig) {\n throw new Error(\"[x402/crossmint] Timed out waiting for Crossmint tx confirmation\");\n }\n\n // 6. Build X-PAYMENT header with pre-broadcast txId\n const payload = {\n x402Version: 2,\n scheme: \"exact\",\n network: accept.network,\n payload: {\n transaction: Buffer.from(unsignedTx.serialize()).toString(\"base64\"),\n txId: sig,\n },\n accepted: {\n scheme: accept.scheme,\n network: accept.network,\n amount: accept.amount,\n asset: accept.asset,\n payTo: accept.payTo,\n },\n };\n const xPayment = Buffer.from(JSON.stringify(payload)).toString(\"base64\");\n\n // 7. Retry with payment\n return fetch(url, {\n ...init,\n headers: { Accept: \"application/json\", \"X-PAYMENT\": xPayment, ...init?.headers },\n });\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relai-fi/x402",
3
- "version": "0.5.19",
3
+ "version": "0.5.21",
4
4
  "description": "Unified x402 payment SDK for Solana, Base, Avalanche, SKALE Base, SKALE BITE, Polygon, and Ethereum. Automatic 402 handling with zero gas fees.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -75,6 +75,11 @@
75
75
  "import": "./dist/react/index.js",
76
76
  "require": "./dist/react/index.cjs"
77
77
  },
78
+ "./crossmint": {
79
+ "types": "./dist/crossmint.d.ts",
80
+ "import": "./dist/crossmint.js",
81
+ "require": "./dist/crossmint.cjs"
82
+ },
78
83
  "./utils": {
79
84
  "types": "./dist/utils/index.d.ts",
80
85
  "import": "./dist/utils/index.js",