@blockrun/llm 0.1.1

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,206 @@
1
+ // src/x402.ts
2
+ import { signTypedData } from "viem/accounts";
3
+ var BASE_CHAIN_ID = 8453;
4
+ var USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
5
+ var SOLANA_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
6
+ var USDC_SOLANA = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
7
+ var SOLANA_USDC_DECIMALS = 6;
8
+ var DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
9
+ var DEFAULT_COMPUTE_UNIT_LIMIT = 8e3;
10
+ var USDC_DOMAIN = {
11
+ name: "USD Coin",
12
+ version: "2",
13
+ chainId: BASE_CHAIN_ID,
14
+ verifyingContract: USDC_BASE
15
+ };
16
+ var TRANSFER_TYPES = {
17
+ TransferWithAuthorization: [
18
+ { name: "from", type: "address" },
19
+ { name: "to", type: "address" },
20
+ { name: "value", type: "uint256" },
21
+ { name: "validAfter", type: "uint256" },
22
+ { name: "validBefore", type: "uint256" },
23
+ { name: "nonce", type: "bytes32" }
24
+ ]
25
+ };
26
+ function createNonce() {
27
+ const bytes = new Uint8Array(32);
28
+ crypto.getRandomValues(bytes);
29
+ return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
30
+ }
31
+ async function createPaymentPayload(privateKey, fromAddress, recipient, amount, network = "eip155:8453", options = {}) {
32
+ const now = Math.floor(Date.now() / 1e3);
33
+ const validAfter = now - 600;
34
+ const validBefore = now + (options.maxTimeoutSeconds || 300);
35
+ const nonce = createNonce();
36
+ const domain = USDC_DOMAIN;
37
+ const signature = await signTypedData({
38
+ privateKey,
39
+ domain,
40
+ types: TRANSFER_TYPES,
41
+ primaryType: "TransferWithAuthorization",
42
+ message: {
43
+ from: fromAddress,
44
+ to: recipient,
45
+ value: BigInt(amount),
46
+ validAfter: BigInt(validAfter),
47
+ validBefore: BigInt(validBefore),
48
+ nonce
49
+ }
50
+ });
51
+ const paymentData = {
52
+ x402Version: 2,
53
+ resource: {
54
+ url: options.resourceUrl || "https://blockrun.ai/api/v1/chat/completions",
55
+ description: options.resourceDescription || "BlockRun AI API call",
56
+ mimeType: "application/json"
57
+ },
58
+ accepted: {
59
+ scheme: "exact",
60
+ network,
61
+ amount,
62
+ asset: USDC_BASE,
63
+ payTo: recipient,
64
+ maxTimeoutSeconds: options.maxTimeoutSeconds || 300,
65
+ extra: { name: "USD Coin", version: "2" }
66
+ },
67
+ payload: {
68
+ signature,
69
+ authorization: {
70
+ from: fromAddress,
71
+ to: recipient,
72
+ value: amount,
73
+ validAfter: validAfter.toString(),
74
+ validBefore: validBefore.toString(),
75
+ nonce
76
+ }
77
+ },
78
+ extensions: options.extensions || {}
79
+ };
80
+ return btoa(JSON.stringify(paymentData));
81
+ }
82
+ async function createSolanaPaymentPayload(secretKey, fromAddress, recipient, amount, feePayer, options = {}) {
83
+ const { Connection, PublicKey, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } = await import("./index.esm-FLTVMT4C.mjs");
84
+ const { getAssociatedTokenAddress, createTransferCheckedInstruction, getMint } = await import("./esm-3BUZROFC.mjs");
85
+ const { Keypair } = await import("./index.esm-FLTVMT4C.mjs");
86
+ const rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
87
+ const connection = new Connection(rpcUrl);
88
+ const keypair = Keypair.fromSecretKey(secretKey);
89
+ const feePayerPubkey = new PublicKey(feePayer);
90
+ const ownerPubkey = keypair.publicKey;
91
+ const tokenMint = new PublicKey(USDC_SOLANA);
92
+ const payToPubkey = new PublicKey(recipient);
93
+ const mintInfo = await getMint(connection, tokenMint);
94
+ const sourceATA = await getAssociatedTokenAddress(tokenMint, ownerPubkey, false);
95
+ const destinationATA = await getAssociatedTokenAddress(tokenMint, payToPubkey, false);
96
+ const { blockhash } = await connection.getLatestBlockhash();
97
+ const setComputeUnitPriceIx = ComputeBudgetProgram.setComputeUnitPrice({
98
+ microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS
99
+ });
100
+ const setComputeUnitLimitIx = ComputeBudgetProgram.setComputeUnitLimit({
101
+ units: DEFAULT_COMPUTE_UNIT_LIMIT
102
+ });
103
+ const transferIx = createTransferCheckedInstruction(
104
+ sourceATA,
105
+ tokenMint,
106
+ destinationATA,
107
+ ownerPubkey,
108
+ BigInt(amount),
109
+ mintInfo.decimals
110
+ );
111
+ const messageV0 = new TransactionMessage({
112
+ payerKey: feePayerPubkey,
113
+ recentBlockhash: blockhash,
114
+ instructions: [setComputeUnitLimitIx, setComputeUnitPriceIx, transferIx]
115
+ }).compileToV0Message();
116
+ const transaction = new VersionedTransaction(messageV0);
117
+ transaction.sign([keypair]);
118
+ const serializedTx = Buffer.from(transaction.serialize()).toString("base64");
119
+ const paymentData = {
120
+ x402Version: 2,
121
+ resource: {
122
+ url: options.resourceUrl || "https://blockrun.ai/api/v1/chat/completions",
123
+ description: options.resourceDescription || "BlockRun AI API call",
124
+ mimeType: "application/json"
125
+ },
126
+ accepted: {
127
+ scheme: "exact",
128
+ network: SOLANA_NETWORK,
129
+ amount,
130
+ asset: USDC_SOLANA,
131
+ payTo: recipient,
132
+ maxTimeoutSeconds: options.maxTimeoutSeconds || 300,
133
+ extra: options.extra || { feePayer }
134
+ },
135
+ payload: {
136
+ transaction: serializedTx
137
+ },
138
+ extensions: options.extensions || {}
139
+ };
140
+ return btoa(JSON.stringify(paymentData));
141
+ }
142
+ function parsePaymentRequired(headerValue) {
143
+ try {
144
+ const decoded = atob(headerValue);
145
+ const parsed = JSON.parse(decoded);
146
+ if (!parsed.accepts || !Array.isArray(parsed.accepts)) {
147
+ throw new Error("Invalid payment required structure: missing or invalid 'accepts' field");
148
+ }
149
+ return parsed;
150
+ } catch (error) {
151
+ if (error instanceof Error) {
152
+ if (error.message.includes("Invalid payment required structure")) {
153
+ throw error;
154
+ }
155
+ throw new Error("Failed to parse payment required header: invalid format");
156
+ }
157
+ throw new Error("Failed to parse payment required header");
158
+ }
159
+ }
160
+ function extractPaymentDetails(paymentRequired, preferredNetwork) {
161
+ const accepts = paymentRequired.accepts || [];
162
+ if (accepts.length === 0) {
163
+ throw new Error("No payment options in payment required response");
164
+ }
165
+ let option = null;
166
+ if (preferredNetwork) {
167
+ option = accepts.find((opt) => opt.network === preferredNetwork) || null;
168
+ }
169
+ if (!option) {
170
+ option = accepts[0];
171
+ }
172
+ const amount = option.amount || option.maxAmountRequired;
173
+ if (!amount) {
174
+ throw new Error("No amount found in payment requirements");
175
+ }
176
+ return {
177
+ amount,
178
+ recipient: option.payTo,
179
+ network: option.network,
180
+ asset: option.asset,
181
+ scheme: option.scheme,
182
+ maxTimeoutSeconds: option.maxTimeoutSeconds || 300,
183
+ extra: option.extra,
184
+ resource: paymentRequired.resource
185
+ };
186
+ }
187
+ function isSolanaNetwork(network) {
188
+ return network.startsWith("solana:");
189
+ }
190
+ function getAvailableNetworks(paymentRequired) {
191
+ return paymentRequired.accepts.map((opt) => opt.network).filter((network) => Boolean(network));
192
+ }
193
+
194
+ export {
195
+ BASE_CHAIN_ID,
196
+ USDC_BASE,
197
+ SOLANA_NETWORK,
198
+ USDC_SOLANA,
199
+ SOLANA_USDC_DECIMALS,
200
+ createPaymentPayload,
201
+ createSolanaPaymentPayload,
202
+ parsePaymentRequired,
203
+ extractPaymentDetails,
204
+ isSolanaNetwork,
205
+ getAvailableNetworks
206
+ };