@joai/warps-adapter-solana 1.0.0-beta.23

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.
package/dist/index.mjs ADDED
@@ -0,0 +1,2305 @@
1
+ // src/chains/solana.ts
2
+ import { WarpChainName as WarpChainName5 } from "@joai/warps";
3
+
4
+ // src/WarpSolanaDataLoader.ts
5
+ import {
6
+ CacheTtl,
7
+ getProviderConfig,
8
+ getWarpChainAssetLogoUrl,
9
+ WarpCache,
10
+ WarpCacheKey
11
+ } from "@joai/warps";
12
+ import { Connection, PublicKey } from "@solana/web3.js";
13
+ import { getMint } from "@solana/spl-token";
14
+
15
+ // src/constants.ts
16
+ var WarpSolanaConstants = {
17
+ ComputeUnitLimit: {
18
+ Default: 2e5,
19
+ Transfer: 5e3,
20
+ TokenTransfer: 1e4,
21
+ ContractCall: 2e5
22
+ },
23
+ PriorityFee: {
24
+ Default: 1e3
25
+ },
26
+ Validation: {
27
+ MinComputeUnits: 1e3,
28
+ MaxComputeUnits: 14e5
29
+ },
30
+ Programs: {
31
+ TokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
32
+ SystemProgram: "11111111111111111111111111111111"
33
+ },
34
+ NativeToken: {
35
+ Identifier: "SOL",
36
+ Decimals: 9
37
+ }
38
+ };
39
+ var SolanaExplorers = /* @__PURE__ */ ((SolanaExplorers2) => {
40
+ SolanaExplorers2["Solscan"] = "solscan";
41
+ SolanaExplorers2["SolscanMainnet"] = "solscan_mainnet";
42
+ SolanaExplorers2["SolscanDevnet"] = "solscan_devnet";
43
+ SolanaExplorers2["SolanaExplorer"] = "solana_explorer";
44
+ SolanaExplorers2["SolanaExplorerMainnet"] = "solana_explorer_mainnet";
45
+ SolanaExplorers2["SolanaExplorerDevnet"] = "solana_explorer_devnet";
46
+ return SolanaExplorers2;
47
+ })(SolanaExplorers || {});
48
+ var SolanaExplorerMap = {
49
+ solana: {
50
+ mainnet: ["solscan_mainnet" /* SolscanMainnet */, "solana_explorer_mainnet" /* SolanaExplorerMainnet */],
51
+ testnet: ["solscan" /* Solscan */, "solana_explorer" /* SolanaExplorer */],
52
+ devnet: ["solscan_devnet" /* SolscanDevnet */, "solana_explorer_devnet" /* SolanaExplorerDevnet */]
53
+ }
54
+ };
55
+ var ExplorerUrls = {
56
+ ["solscan" /* Solscan */]: "https://solscan.io",
57
+ ["solscan_mainnet" /* SolscanMainnet */]: "https://solscan.io",
58
+ ["solscan_devnet" /* SolscanDevnet */]: "https://solscan.io",
59
+ ["solana_explorer" /* SolanaExplorer */]: "https://explorer.solana.com",
60
+ ["solana_explorer_mainnet" /* SolanaExplorerMainnet */]: "https://explorer.solana.com",
61
+ ["solana_explorer_devnet" /* SolanaExplorerDevnet */]: "https://explorer.solana.com"
62
+ };
63
+ var SolanaExplorerNames = {
64
+ mainnet: ["solscan_mainnet" /* SolscanMainnet */, "solana_explorer_mainnet" /* SolanaExplorerMainnet */],
65
+ testnet: ["solscan" /* Solscan */, "solana_explorer" /* SolanaExplorer */],
66
+ devnet: ["solscan_devnet" /* SolscanDevnet */, "solana_explorer_devnet" /* SolanaExplorerDevnet */]
67
+ };
68
+ var SolanaExplorerUrls = ExplorerUrls;
69
+ var X402SolanaNetworkIdentifiers = {
70
+ Mainnet: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
71
+ Devnet: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
72
+ };
73
+ var SupportedX402SolanaNetworks = [X402SolanaNetworkIdentifiers.Mainnet, X402SolanaNetworkIdentifiers.Devnet];
74
+
75
+ // src/tokens.ts
76
+ import { WarpChainName as WarpChainName4 } from "@joai/warps";
77
+
78
+ // src/tokens/solana-mainnet.ts
79
+ import { WarpChainName } from "@joai/warps";
80
+ var SolanaChain = WarpChainName.Solana;
81
+ var SolanaMainnetTokens = [
82
+ {
83
+ chain: SolanaChain,
84
+ identifier: "SOL",
85
+ name: "SOL",
86
+ symbol: "SOL",
87
+ decimals: 9,
88
+ logoUrl: "https://assets.coingecko.com/coins/images/4128/small/solana.png"
89
+ },
90
+ {
91
+ chain: SolanaChain,
92
+ identifier: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
93
+ name: "USD Coin",
94
+ symbol: "USDC",
95
+ decimals: 6,
96
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
97
+ },
98
+ {
99
+ chain: SolanaChain,
100
+ identifier: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
101
+ name: "Tether USD",
102
+ symbol: "USDT",
103
+ decimals: 6,
104
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
105
+ },
106
+ {
107
+ chain: SolanaChain,
108
+ identifier: "So11111111111111111111111111111111111111112",
109
+ name: "Wrapped SOL",
110
+ symbol: "WSOL",
111
+ decimals: 9,
112
+ logoUrl: "https://assets.coingecko.com/coins/images/4128/small/solana.png"
113
+ },
114
+ {
115
+ chain: SolanaChain,
116
+ identifier: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh",
117
+ name: "Wrapped Bitcoin",
118
+ symbol: "WBTC",
119
+ decimals: 8,
120
+ logoUrl: "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png"
121
+ },
122
+ {
123
+ chain: SolanaChain,
124
+ identifier: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs",
125
+ name: "Ethereum (Wormhole)",
126
+ symbol: "ETH",
127
+ decimals: 8,
128
+ logoUrl: "https://assets.coingecko.com/coins/images/279/small/ethereum.png"
129
+ },
130
+ {
131
+ chain: SolanaChain,
132
+ identifier: "7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj",
133
+ name: "Orca",
134
+ symbol: "ORCA",
135
+ decimals: 6,
136
+ logoUrl: "https://assets.coingecko.com/coins/images/17547/small/orca.png"
137
+ },
138
+ {
139
+ chain: SolanaChain,
140
+ identifier: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So",
141
+ name: "Marinade SOL",
142
+ symbol: "mSOL",
143
+ decimals: 9,
144
+ logoUrl: "https://assets.coingecko.com/coins/images/17752/small/mSOL.png"
145
+ },
146
+ {
147
+ chain: SolanaChain,
148
+ identifier: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn",
149
+ name: "JitoSOL",
150
+ symbol: "JitoSOL",
151
+ decimals: 9,
152
+ logoUrl: "https://assets.coingecko.com/coins/images/30168/small/jitosol.png"
153
+ },
154
+ {
155
+ chain: SolanaChain,
156
+ identifier: "bSo13r4TkiE4KumL71LsHTPpL2suBYJxqsd4P6Bwv11",
157
+ name: "bSOL",
158
+ symbol: "bSOL",
159
+ decimals: 9,
160
+ logoUrl: "https://assets.coingecko.com/coins/images/30167/small/bsol.png"
161
+ },
162
+ {
163
+ chain: SolanaChain,
164
+ identifier: "7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT",
165
+ name: "UXD Stablecoin",
166
+ symbol: "UXD",
167
+ decimals: 6,
168
+ logoUrl: "https://assets.coingecko.com/coins/images/25342/small/uxd.png"
169
+ },
170
+ {
171
+ chain: SolanaChain,
172
+ identifier: "A9mUU4qviSctJVPJdBJWkb28deg915LYJKrzQ19ji3FM",
173
+ name: "USD Coin (Wormhole)",
174
+ symbol: "USDCet",
175
+ decimals: 6,
176
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
177
+ }
178
+ ];
179
+
180
+ // src/tokens/solana-devnet.ts
181
+ import { WarpChainName as WarpChainName2 } from "@joai/warps";
182
+ var SolanaChain2 = WarpChainName2.Solana;
183
+ var SolanaDevnetTokens = [
184
+ {
185
+ chain: SolanaChain2,
186
+ identifier: "SOL",
187
+ name: "SOL",
188
+ symbol: "SOL",
189
+ decimals: 9,
190
+ logoUrl: "https://assets.coingecko.com/coins/images/4128/small/solana.png"
191
+ },
192
+ {
193
+ chain: SolanaChain2,
194
+ identifier: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
195
+ name: "USD Coin",
196
+ symbol: "USDC",
197
+ decimals: 6,
198
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
199
+ },
200
+ {
201
+ chain: SolanaChain2,
202
+ identifier: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
203
+ name: "Tether USD",
204
+ symbol: "USDT",
205
+ decimals: 6,
206
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
207
+ },
208
+ {
209
+ chain: SolanaChain2,
210
+ identifier: "So11111111111111111111111111111111111111112",
211
+ name: "Wrapped SOL",
212
+ symbol: "WSOL",
213
+ decimals: 9,
214
+ logoUrl: "https://assets.coingecko.com/coins/images/4128/small/solana.png"
215
+ }
216
+ ];
217
+
218
+ // src/tokens/solana-testnet.ts
219
+ import { WarpChainName as WarpChainName3 } from "@joai/warps";
220
+ var SolanaChain3 = WarpChainName3.Solana;
221
+ var SolanaTestnetTokens = [
222
+ {
223
+ chain: SolanaChain3,
224
+ identifier: "SOL",
225
+ name: "SOL",
226
+ symbol: "SOL",
227
+ decimals: 9,
228
+ logoUrl: "https://assets.coingecko.com/coins/images/4128/small/solana.png"
229
+ },
230
+ {
231
+ chain: SolanaChain3,
232
+ identifier: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
233
+ name: "USD Coin",
234
+ symbol: "USDC",
235
+ decimals: 6,
236
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
237
+ },
238
+ {
239
+ chain: SolanaChain3,
240
+ identifier: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
241
+ name: "Tether USD",
242
+ symbol: "USDT",
243
+ decimals: 6,
244
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
245
+ },
246
+ {
247
+ chain: SolanaChain3,
248
+ identifier: "So11111111111111111111111111111111111111112",
249
+ name: "Wrapped SOL",
250
+ symbol: "WSOL",
251
+ decimals: 9,
252
+ logoUrl: "https://assets.coingecko.com/coins/images/4128/small/solana.png"
253
+ }
254
+ ];
255
+
256
+ // src/tokens.ts
257
+ var KnownTokens = {
258
+ [WarpChainName4.Solana]: {
259
+ mainnet: SolanaMainnetTokens,
260
+ testnet: SolanaTestnetTokens,
261
+ devnet: SolanaDevnetTokens
262
+ }
263
+ };
264
+ var findKnownTokenById = (chain, env, id) => {
265
+ const chainTokens = KnownTokens[chain]?.[env] || [];
266
+ return chainTokens.find((token) => token.identifier === id) || null;
267
+ };
268
+ var getKnownTokensForChain = (chainName, env) => {
269
+ return KnownTokens[chainName]?.[env] || [];
270
+ };
271
+
272
+ // src/WarpSolanaDataLoader.ts
273
+ var WarpSolanaDataLoader = class {
274
+ constructor(config, chain) {
275
+ this.config = config;
276
+ this.chain = chain;
277
+ const providerConfig = getProviderConfig(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
278
+ this.connection = new Connection(providerConfig.url, "confirmed");
279
+ this.cache = new WarpCache(config.env, config.cache);
280
+ }
281
+ async getAccount(address) {
282
+ try {
283
+ const publicKey = new PublicKey(address);
284
+ const balance = await this.connection.getBalance(publicKey);
285
+ return {
286
+ chain: this.chain.name,
287
+ address,
288
+ balance: BigInt(balance)
289
+ };
290
+ } catch (error) {
291
+ throw new Error(`Failed to get account: ${error}`);
292
+ }
293
+ }
294
+ async getAccountAssets(address) {
295
+ try {
296
+ const account = await this.getAccount(address);
297
+ const tokenBalances = await this.getTokenBalances(address);
298
+ let assets = account.balance > 0n ? [{ ...this.chain.nativeToken, amount: account.balance }] : [];
299
+ for (const tokenBalance of tokenBalances) {
300
+ if (tokenBalance.balance > 0n) {
301
+ assets.push({
302
+ chain: this.chain.name,
303
+ identifier: tokenBalance.tokenAddress,
304
+ name: tokenBalance.metadata.name,
305
+ symbol: tokenBalance.metadata.symbol,
306
+ amount: tokenBalance.balance,
307
+ decimals: tokenBalance.metadata.decimals,
308
+ logoUrl: tokenBalance.metadata.logoUrl || ""
309
+ });
310
+ }
311
+ }
312
+ return assets;
313
+ } catch (error) {
314
+ return [];
315
+ }
316
+ }
317
+ async getAsset(identifier) {
318
+ try {
319
+ if (identifier === this.chain.nativeToken.identifier || identifier === "SOL") {
320
+ return this.chain.nativeToken;
321
+ }
322
+ const cacheKey = WarpCacheKey.Asset(this.config.env, this.chain.name, identifier);
323
+ const cachedAsset = this.cache.get(cacheKey);
324
+ if (cachedAsset) {
325
+ return cachedAsset;
326
+ }
327
+ const env = this.config.env === "mainnet" ? "mainnet" : this.config.env === "devnet" ? "devnet" : "testnet";
328
+ const knownToken = findKnownTokenById(this.chain.name, env, identifier);
329
+ if (knownToken) {
330
+ return {
331
+ chain: this.chain.name,
332
+ identifier,
333
+ name: knownToken.name,
334
+ symbol: knownToken.symbol,
335
+ amount: 0n,
336
+ decimals: knownToken.decimals,
337
+ logoUrl: knownToken.logoUrl
338
+ };
339
+ }
340
+ const metadata = await this.getTokenMetadata(identifier);
341
+ const asset = {
342
+ chain: this.chain.name,
343
+ identifier,
344
+ name: metadata.name,
345
+ symbol: metadata.symbol,
346
+ amount: 0n,
347
+ decimals: metadata.decimals,
348
+ logoUrl: metadata.logoUrl
349
+ };
350
+ this.cache.set(cacheKey, asset, CacheTtl.OneHour);
351
+ return asset;
352
+ } catch (error) {
353
+ return null;
354
+ }
355
+ }
356
+ async getAction(identifier, awaitCompleted = false) {
357
+ const signature = identifier;
358
+ if (awaitCompleted) {
359
+ const tx = await this.waitForTransaction(signature);
360
+ if (!tx) {
361
+ return this.createFailedAction(signature, "Transaction not found after waiting for completion");
362
+ }
363
+ return this.parseTransactionToAction(tx, signature);
364
+ }
365
+ try {
366
+ const tx = await this.connection.getTransaction(signature, {
367
+ commitment: "confirmed",
368
+ maxSupportedTransactionVersion: 0
369
+ });
370
+ if (!tx) return null;
371
+ return this.parseTransactionToAction(tx, signature);
372
+ } catch {
373
+ return null;
374
+ }
375
+ }
376
+ async getAccountActions(address, options) {
377
+ return [];
378
+ }
379
+ async getTokenBalances(address) {
380
+ try {
381
+ const publicKey = new PublicKey(address);
382
+ const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(publicKey, {
383
+ programId: new PublicKey(WarpSolanaConstants.Programs.TokenProgram)
384
+ });
385
+ const env = this.config.env === "mainnet" ? "mainnet" : this.config.env === "devnet" ? "devnet" : "testnet";
386
+ const knownTokens = getKnownTokensForChain(this.chain.name, env);
387
+ const balances = await Promise.all(
388
+ tokenAccounts.value.map(async (tokenAccount) => {
389
+ const mintAddress = tokenAccount.account.data.parsed.info.mint;
390
+ const balance = BigInt(tokenAccount.account.data.parsed.info.tokenAmount.amount);
391
+ const decimals = tokenAccount.account.data.parsed.info.tokenAmount.decimals;
392
+ const knownToken = knownTokens.find((token) => token.identifier === mintAddress);
393
+ if (knownToken) {
394
+ return {
395
+ tokenAddress: mintAddress,
396
+ balance,
397
+ metadata: {
398
+ name: knownToken.name,
399
+ symbol: knownToken.symbol,
400
+ decimals: knownToken.decimals,
401
+ logoUrl: getWarpChainAssetLogoUrl(knownToken, this.config) || ""
402
+ }
403
+ };
404
+ }
405
+ const metadata = await this.getTokenMetadata(mintAddress);
406
+ return {
407
+ tokenAddress: mintAddress,
408
+ balance,
409
+ metadata: {
410
+ name: metadata.name,
411
+ symbol: metadata.symbol,
412
+ decimals: metadata.decimals || decimals,
413
+ logoUrl: metadata.logoUrl
414
+ }
415
+ };
416
+ })
417
+ );
418
+ return balances.filter((b) => b.balance > 0n);
419
+ } catch (error) {
420
+ return [];
421
+ }
422
+ }
423
+ async getTokenMetadata(tokenAddress) {
424
+ try {
425
+ const mintPublicKey = new PublicKey(tokenAddress);
426
+ const mintInfo = await getMint(this.connection, mintPublicKey);
427
+ return {
428
+ name: "Unknown Token",
429
+ symbol: "UNKNOWN",
430
+ decimals: mintInfo.decimals,
431
+ logoUrl: ""
432
+ };
433
+ } catch (error) {
434
+ return {
435
+ name: "Unknown Token",
436
+ symbol: "UNKNOWN",
437
+ decimals: WarpSolanaConstants.NativeToken.Decimals,
438
+ logoUrl: ""
439
+ };
440
+ }
441
+ }
442
+ async waitForTransaction(signature) {
443
+ const maxWaitTime = 3e5;
444
+ const startTime = Date.now();
445
+ let delay = 1e3;
446
+ let lastError = null;
447
+ let attempts = 0;
448
+ while (Date.now() - startTime < maxWaitTime) {
449
+ attempts++;
450
+ try {
451
+ const tx = await this.tryFetchTransaction(signature);
452
+ if (tx) return tx;
453
+ } catch (err) {
454
+ lastError = err;
455
+ }
456
+ if (Date.now() - startTime < maxWaitTime) {
457
+ delay = this.calculateBackoffDelay(delay, attempts, lastError);
458
+ await new Promise((resolve) => setTimeout(resolve, delay));
459
+ }
460
+ }
461
+ try {
462
+ return await this.connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 0 });
463
+ } catch {
464
+ return null;
465
+ }
466
+ }
467
+ async tryFetchTransaction(signature) {
468
+ try {
469
+ const confirmation = await Promise.race([
470
+ this.connection.confirmTransaction(signature, "finalized"),
471
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), 6e4))
472
+ ]);
473
+ if (confirmation) {
474
+ const tx = await this.connection.getTransaction(signature, { commitment: "finalized", maxSupportedTransactionVersion: 0 });
475
+ if (tx) return tx;
476
+ }
477
+ } catch {
478
+ }
479
+ try {
480
+ const tx = await this.connection.getTransaction(signature, { commitment: "finalized", maxSupportedTransactionVersion: 0 });
481
+ if (tx) return tx;
482
+ } catch {
483
+ }
484
+ try {
485
+ return await this.connection.getTransaction(signature, { commitment: "confirmed", maxSupportedTransactionVersion: 0 });
486
+ } catch {
487
+ return null;
488
+ }
489
+ }
490
+ calculateBackoffDelay(currentDelay, attempts, lastError) {
491
+ if (lastError?.message?.includes("429") || lastError?.message?.includes("rate limit")) {
492
+ return Math.min(currentDelay * 2, 3e4);
493
+ }
494
+ if (attempts % 10 === 0) {
495
+ return 2e3;
496
+ }
497
+ return Math.min(currentDelay * 1.1, 15e3);
498
+ }
499
+ createFailedAction(signature, error) {
500
+ return {
501
+ chain: this.chain.name,
502
+ id: signature,
503
+ receiver: "",
504
+ sender: "",
505
+ value: 0n,
506
+ function: "",
507
+ status: "failed",
508
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
509
+ error,
510
+ tx: {
511
+ signature,
512
+ slot: 0,
513
+ blockTime: null,
514
+ err: { message: error }
515
+ }
516
+ };
517
+ }
518
+ parseTransactionToAction(tx, signature) {
519
+ const slot = tx.slot;
520
+ const blockTime = tx.blockTime ? new Date(tx.blockTime * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
521
+ const accountKeys = this.extractAccountKeys(tx.transaction.message);
522
+ const sender = accountKeys[0]?.toBase58() || "";
523
+ const receiver = accountKeys.length > 1 ? accountKeys[1]?.toBase58() || "" : "";
524
+ const value = this.calculateTransactionValue(tx.meta);
525
+ const status = tx.meta?.err ? "failed" : "success";
526
+ const functionName = this.determineFunctionName(tx.transaction.message);
527
+ return {
528
+ chain: this.chain.name,
529
+ id: signature,
530
+ receiver,
531
+ sender,
532
+ value,
533
+ function: functionName,
534
+ status,
535
+ createdAt: blockTime,
536
+ error: tx.meta?.err ? JSON.stringify(tx.meta.err) : null,
537
+ tx: {
538
+ signature,
539
+ slot,
540
+ blockTime,
541
+ err: tx.meta?.err || null
542
+ }
543
+ };
544
+ }
545
+ extractAccountKeys(message) {
546
+ if ("staticAccountKeys" in message) {
547
+ return message.staticAccountKeys || [];
548
+ }
549
+ try {
550
+ const allKeys = message.getAccountKeys?.();
551
+ if (allKeys) {
552
+ return allKeys.keySegments().flat() || [];
553
+ }
554
+ } catch {
555
+ }
556
+ return [];
557
+ }
558
+ calculateTransactionValue(meta) {
559
+ const preBalances = meta?.preBalances || [];
560
+ const postBalances = meta?.postBalances || [];
561
+ if (preBalances.length === 0 || postBalances.length === 0) return 0n;
562
+ return BigInt(Math.abs(postBalances[0] - preBalances[0]));
563
+ }
564
+ determineFunctionName(message) {
565
+ let compiledInstructions = [];
566
+ if ("compiledInstructions" in message && Array.isArray(message.compiledInstructions)) {
567
+ compiledInstructions = message.compiledInstructions;
568
+ }
569
+ if (compiledInstructions.length === 0) return "transfer";
570
+ return compiledInstructions[0]?.programIdIndex !== void 0 ? "contract_call" : "transfer";
571
+ }
572
+ };
573
+
574
+ // src/WarpSolanaExecutor.ts
575
+ import { createAssociatedTokenAccountInstruction, createTransferInstruction, getAssociatedTokenAddress } from "@solana/spl-token";
576
+ import { ComputeBudgetProgram, Connection as Connection3, MessageV0, PublicKey as PublicKey3, SystemProgram, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
577
+ import {
578
+ applyOutputToMessages,
579
+ extractResolvedInputValues as extractResolvedInputValues2,
580
+ getNextInfo,
581
+ getProviderConfig as getProviderConfig3,
582
+ getWarpActionByIndex,
583
+ getWarpWalletAddressFromConfig as getWarpWalletAddressFromConfig2
584
+ } from "@joai/warps";
585
+
586
+ // src/WarpSolanaOutput.ts
587
+ import {
588
+ evaluateOutputCommon,
589
+ extractResolvedInputValues,
590
+ getProviderConfig as getProviderConfig2,
591
+ getWarpWalletAddressFromConfig,
592
+ parseOutputOutIndex,
593
+ WarpConstants as WarpConstants2,
594
+ WarpCache as WarpCache2,
595
+ WarpCacheKey as WarpCacheKey2
596
+ } from "@joai/warps";
597
+ import { Connection as Connection2 } from "@solana/web3.js";
598
+
599
+ // src/WarpSolanaSerializer.ts
600
+ import {
601
+ WarpConstants,
602
+ WarpSerializer
603
+ } from "@joai/warps";
604
+ import { PublicKey as PublicKey2 } from "@solana/web3.js";
605
+ import bs58 from "bs58";
606
+ var WarpSolanaSerializer = class {
607
+ constructor() {
608
+ this.coreSerializer = new WarpSerializer();
609
+ }
610
+ typedToString(value) {
611
+ if (value && typeof value === "object" && "toBase58" in value && typeof value.toBase58 === "function") {
612
+ return `address:${value.toBase58()}`;
613
+ }
614
+ if (typeof value === "string") {
615
+ if (value.length >= 32 && value.length <= 44) {
616
+ try {
617
+ const pubkey = new PublicKey2(value);
618
+ if (pubkey.toBase58() === value && /^[1-9A-HJ-NP-Za-km-z]+$/.test(value)) {
619
+ return `address:${value}`;
620
+ }
621
+ } catch {
622
+ }
623
+ }
624
+ if (value.startsWith("0x") || /^[0-9a-fA-F]+$/.test(value)) {
625
+ return `hex:${value}`;
626
+ }
627
+ return `string:${value}`;
628
+ }
629
+ if (typeof value === "number") {
630
+ if (Number.isInteger(value)) {
631
+ if (value >= 0 && value <= 255) return `uint8:${value}`;
632
+ if (value >= 0 && value <= 65535) return `uint16:${value}`;
633
+ if (value >= 0 && value <= 4294967295) return `uint32:${value}`;
634
+ return `uint64:${value}`;
635
+ }
636
+ return `string:${value}`;
637
+ }
638
+ if (typeof value === "bigint") {
639
+ return `biguint:${value.toString()}`;
640
+ }
641
+ if (typeof value === "boolean") {
642
+ return `boolean:${value}`;
643
+ }
644
+ if (value instanceof PublicKey2) {
645
+ return `address:${value.toBase58()}`;
646
+ }
647
+ if (value instanceof Uint8Array) {
648
+ return `hex:${bs58.encode(value)}`;
649
+ }
650
+ if (typeof value === "object" && value !== null && "identifier" in value && "amount" in value) {
651
+ const asset = value;
652
+ if (asset.decimals !== void 0) {
653
+ return `asset:${asset.identifier}${WarpConstants.ArgCompositeSeparator}${asset.amount.toString()}${WarpConstants.ArgCompositeSeparator}${asset.decimals}`;
654
+ }
655
+ return `asset:${asset.identifier}${WarpConstants.ArgCompositeSeparator}${asset.amount.toString()}`;
656
+ }
657
+ if (Array.isArray(value)) {
658
+ if (value.length === 0) return `list:string:`;
659
+ const types = value.map((item) => this.typedToString(item).split(WarpConstants.ArgParamsSeparator)[0]);
660
+ const type = types[0];
661
+ const values = value.map((item) => this.typedToString(item).split(WarpConstants.ArgParamsSeparator)[1]);
662
+ return `list:${type}:${values.join(",")}`;
663
+ }
664
+ if (value === null || value === void 0) {
665
+ return `string:null`;
666
+ }
667
+ return `string:${String(value)}`;
668
+ }
669
+ typedToNative(value) {
670
+ const stringValue = this.typedToString(value);
671
+ const [type, ...valueParts] = stringValue.split(WarpConstants.ArgParamsSeparator);
672
+ const nativeValue = valueParts.join(WarpConstants.ArgParamsSeparator);
673
+ return [type, this.parseNativeValue(type, nativeValue)];
674
+ }
675
+ nativeToTyped(type, value) {
676
+ switch (type) {
677
+ case "string":
678
+ return String(value);
679
+ case "uint8":
680
+ case "uint16":
681
+ case "uint32":
682
+ case "uint64":
683
+ return BigInt(value);
684
+ case "biguint":
685
+ return BigInt(value);
686
+ case "boolean":
687
+ return Boolean(value);
688
+ case "address":
689
+ return String(value);
690
+ case "hex":
691
+ return String(value);
692
+ case "asset":
693
+ if (typeof value === "object" && value !== null && "identifier" in value && "amount" in value) {
694
+ return value;
695
+ }
696
+ return value;
697
+ default:
698
+ if (type.startsWith("list:")) {
699
+ const [, itemType, itemsStr] = type.split(":");
700
+ if (!itemsStr) return [];
701
+ const items = itemsStr.split(",");
702
+ return items.map((item) => this.nativeToTyped(itemType, item));
703
+ }
704
+ return String(value);
705
+ }
706
+ }
707
+ nativeToType(type) {
708
+ switch (type) {
709
+ case "string":
710
+ return "string";
711
+ case "uint8":
712
+ case "uint16":
713
+ case "uint32":
714
+ case "uint64":
715
+ case "biguint":
716
+ return "bigint";
717
+ case "boolean":
718
+ return "boolean";
719
+ case "address":
720
+ return "string";
721
+ case "hex":
722
+ return "string";
723
+ default:
724
+ return "string";
725
+ }
726
+ }
727
+ stringToTyped(value) {
728
+ const parts = value.split(WarpConstants.ArgParamsSeparator, 2);
729
+ if (parts.length < 2) {
730
+ return value;
731
+ }
732
+ const [type, stringValue] = parts;
733
+ switch (type) {
734
+ case "string":
735
+ return stringValue;
736
+ case "uint8":
737
+ case "uint16":
738
+ case "uint32":
739
+ case "uint64":
740
+ return BigInt(stringValue);
741
+ case "biguint":
742
+ return BigInt(stringValue);
743
+ case "boolean":
744
+ return stringValue === "true";
745
+ case "address":
746
+ return stringValue;
747
+ case "hex":
748
+ return stringValue;
749
+ case "asset":
750
+ const assetParts = stringValue.split(WarpConstants.ArgCompositeSeparator);
751
+ const identifier = assetParts[0] || "";
752
+ const amount = assetParts[1] ? BigInt(assetParts[1]) : 0n;
753
+ const decimals = assetParts[2] ? parseInt(assetParts[2], 10) : void 0;
754
+ return { identifier, amount, decimals };
755
+ default:
756
+ if (type.startsWith("list:")) {
757
+ const [, itemType, itemsStr] = type.split(":");
758
+ if (!itemsStr) return [];
759
+ const items = itemsStr.split(",");
760
+ return items.map((item) => this.stringToTyped(`${itemType}:${item}`));
761
+ }
762
+ return stringValue;
763
+ }
764
+ }
765
+ parseNativeValue(type, value) {
766
+ switch (type) {
767
+ case "string":
768
+ return value;
769
+ case "uint8":
770
+ case "uint16":
771
+ case "uint32":
772
+ case "uint64":
773
+ case "biguint":
774
+ return BigInt(value);
775
+ case "boolean":
776
+ return value === "true";
777
+ case "address":
778
+ return value;
779
+ case "hex":
780
+ return value;
781
+ default:
782
+ return value;
783
+ }
784
+ }
785
+ };
786
+
787
+ // src/WarpSolanaOutput.ts
788
+ var WarpSolanaOutput = class {
789
+ constructor(config, chain) {
790
+ this.config = config;
791
+ this.chain = chain;
792
+ this.serializer = new WarpSolanaSerializer();
793
+ const providerConfig = getProviderConfig2(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
794
+ this.connection = new Connection2(providerConfig.url, "confirmed");
795
+ this.cache = new WarpCache2(config.env, config.cache);
796
+ }
797
+ async getActionExecution(warp, actionIndex, tx) {
798
+ const inputs = this.cache.get(WarpCacheKey2.WarpExecutable(this.config.env, warp.meta?.hash || "", actionIndex)) ?? [];
799
+ const resolvedInputs = extractResolvedInputValues(inputs);
800
+ if (!tx) {
801
+ return this.createFailedExecution(warp, actionIndex, resolvedInputs);
802
+ }
803
+ if ("status" in tx && typeof tx.status === "string") {
804
+ return this.handleWarpChainAction(warp, actionIndex, tx, resolvedInputs);
805
+ }
806
+ if (typeof tx === "string") {
807
+ return this.handleTransactionSignature(warp, actionIndex, tx, resolvedInputs);
808
+ }
809
+ return this.createFailedExecution(warp, actionIndex, resolvedInputs);
810
+ }
811
+ createFailedExecution(warp, actionIndex, resolvedInputs = []) {
812
+ return {
813
+ status: "error",
814
+ warp,
815
+ action: actionIndex,
816
+ user: getWarpWalletAddressFromConfig(this.config, this.chain.name),
817
+ txHash: "",
818
+ tx: null,
819
+ next: null,
820
+ values: { string: [], native: [], mapped: {} },
821
+ output: {},
822
+ messages: {},
823
+ destination: null,
824
+ resolvedInputs
825
+ };
826
+ }
827
+ async handleWarpChainAction(warp, actionIndex, tx, resolvedInputs = []) {
828
+ const isPending = tx.status === "pending";
829
+ const success = tx.status === "success";
830
+ const transactionHash = tx.id || tx.tx?.signature || "";
831
+ if (isPending) {
832
+ throw new Error(`Transaction ${transactionHash} is still pending. Execution should only proceed after finalization.`);
833
+ }
834
+ const slot = tx.tx?.slot || 0;
835
+ const blockTime = tx.tx?.blockTime || 0;
836
+ const rawValues = [transactionHash, slot.toString(), blockTime.toString()];
837
+ const stringValues = rawValues.map(String);
838
+ return {
839
+ status: success ? "success" : "error",
840
+ warp,
841
+ action: actionIndex,
842
+ user: getWarpWalletAddressFromConfig(this.config, this.chain.name),
843
+ txHash: transactionHash,
844
+ tx,
845
+ next: null,
846
+ values: { string: stringValues, native: rawValues, mapped: {} },
847
+ output: {},
848
+ messages: {},
849
+ destination: null,
850
+ resolvedInputs
851
+ };
852
+ }
853
+ async handleTransactionSignature(warp, actionIndex, signature, resolvedInputs = []) {
854
+ try {
855
+ const tx = await this.connection.getTransaction(signature, {
856
+ commitment: "confirmed",
857
+ maxSupportedTransactionVersion: 0
858
+ });
859
+ if (!tx) {
860
+ return this.createFailedExecution(warp, actionIndex, resolvedInputs);
861
+ }
862
+ const success = !tx.meta?.err;
863
+ const slot = tx.slot;
864
+ const blockTime = tx.blockTime || 0;
865
+ const fee = tx.meta?.fee || 0;
866
+ const rawValues = [signature, slot.toString(), blockTime.toString(), fee.toString()];
867
+ const stringValues = rawValues.map(String);
868
+ return {
869
+ status: success ? "success" : "error",
870
+ warp,
871
+ action: actionIndex,
872
+ user: getWarpWalletAddressFromConfig(this.config, this.chain.name),
873
+ txHash: signature,
874
+ tx: {
875
+ signature,
876
+ slot,
877
+ blockTime,
878
+ fee,
879
+ err: tx.meta?.err || null
880
+ },
881
+ next: null,
882
+ values: { string: stringValues, native: rawValues, mapped: {} },
883
+ output: {},
884
+ messages: {},
885
+ destination: null,
886
+ resolvedInputs
887
+ };
888
+ } catch (error) {
889
+ return this.createFailedExecution(warp, actionIndex, resolvedInputs);
890
+ }
891
+ }
892
+ async extractQueryOutput(warp, typedValues, actionIndex, inputs) {
893
+ const stringValues = typedValues.map((t) => this.serializer.typedToString(t));
894
+ const nativeValues = typedValues.map((t) => this.serializer.typedToNative(t)[1]);
895
+ const values = { string: stringValues, native: nativeValues, mapped: {} };
896
+ let output = {};
897
+ if (!warp.output) return { values, output };
898
+ const getNestedValue = (path) => {
899
+ const indices = path.split(".").slice(1).map((i) => parseInt(i) - 1);
900
+ if (indices.length === 0) return void 0;
901
+ let value = nativeValues[indices[0]];
902
+ for (let i = 1; i < indices.length; i++) {
903
+ if (value === void 0 || value === null) return void 0;
904
+ value = value[indices[i]];
905
+ }
906
+ return value;
907
+ };
908
+ for (const [key, path] of Object.entries(warp.output)) {
909
+ if (path.startsWith(WarpConstants2.Transform.Prefix)) continue;
910
+ const currentActionIndex = parseOutputOutIndex(path);
911
+ if (currentActionIndex !== null && currentActionIndex !== actionIndex) {
912
+ output[key] = null;
913
+ continue;
914
+ }
915
+ if (path.startsWith("out.") || path === "out" || path.startsWith("out[")) {
916
+ output[key] = getNestedValue(path) || null;
917
+ } else {
918
+ output[key] = path;
919
+ }
920
+ }
921
+ return { values, output: await evaluateOutputCommon(warp, output, actionIndex, inputs, this.serializer.coreSerializer, this.config) };
922
+ }
923
+ async getTransactionStatus(txHash) {
924
+ try {
925
+ const tx = await this.connection.getTransaction(txHash, {
926
+ commitment: "confirmed",
927
+ maxSupportedTransactionVersion: 0
928
+ });
929
+ if (!tx) {
930
+ return { status: "pending" };
931
+ }
932
+ return {
933
+ status: tx.meta?.err ? "failed" : "confirmed",
934
+ blockNumber: tx.slot,
935
+ gasUsed: BigInt(tx.meta?.fee || 0)
936
+ };
937
+ } catch (error) {
938
+ throw new Error(`Failed to get transaction status: ${error}`);
939
+ }
940
+ }
941
+ async getTransactionReceipt(txHash) {
942
+ try {
943
+ const tx = await this.connection.getTransaction(txHash, {
944
+ commitment: "confirmed",
945
+ maxSupportedTransactionVersion: 0
946
+ });
947
+ if (!tx) {
948
+ return null;
949
+ }
950
+ return {
951
+ signature: txHash,
952
+ slot: tx.slot,
953
+ blockTime: tx.blockTime,
954
+ fee: tx.meta?.fee || 0,
955
+ err: tx.meta?.err || null
956
+ };
957
+ } catch (error) {
958
+ return null;
959
+ }
960
+ }
961
+ };
962
+
963
+ // src/WarpSolanaExecutor.ts
964
+ var WarpSolanaExecutor = class {
965
+ constructor(config, chain) {
966
+ this.config = config;
967
+ this.chain = chain;
968
+ this.serializer = new WarpSolanaSerializer();
969
+ const providerConfig = getProviderConfig3(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
970
+ this.connection = new Connection3(providerConfig.url, "confirmed");
971
+ this.output = new WarpSolanaOutput(config, this.chain);
972
+ }
973
+ async createTransaction(executable) {
974
+ const action = getWarpActionByIndex(executable.warp, executable.action);
975
+ let tx = null;
976
+ if (action.type === "transfer") {
977
+ tx = await this.createTransferTransaction(executable);
978
+ } else if (action.type === "contract") {
979
+ tx = await this.createContractCallTransaction(executable);
980
+ } else if (action.type === "query") {
981
+ throw new Error("WarpSolanaExecutor: Invalid action type for createTransaction; Use executeQuery instead");
982
+ } else if (action.type === "collect") {
983
+ throw new Error("WarpSolanaExecutor: Invalid action type for createTransaction; Use executeCollect instead");
984
+ }
985
+ if (!tx) throw new Error(`WarpSolanaExecutor: Invalid action type (${action.type})`);
986
+ return tx;
987
+ }
988
+ async createTransferTransaction(executable) {
989
+ const userWallet = getWarpWalletAddressFromConfig2(this.config, executable.chain.name);
990
+ if (!userWallet) throw new Error("WarpSolanaExecutor: createTransfer - user address not set");
991
+ if (!executable.destination) throw new Error("WarpSolanaExecutor: Destination address is required");
992
+ const destinationPubkey = this.toPublicKey(executable.destination, "Invalid destination address");
993
+ const fromPubkey = this.toPublicKey(userWallet, "Invalid user wallet address");
994
+ if (executable.transfers && executable.transfers.length > 0) {
995
+ return this.createTokenTransferTransaction(executable, userWallet, destinationPubkey);
996
+ }
997
+ const instructions = [];
998
+ if (executable.value > 0n) {
999
+ instructions.push(SystemProgram.transfer({ fromPubkey, toPubkey: destinationPubkey, lamports: Number(executable.value) }));
1000
+ }
1001
+ if (executable.data) {
1002
+ const data = this.serializer.stringToTyped(executable.data);
1003
+ if (data && typeof data === "string") {
1004
+ const dataBuffer = Buffer.from(data, "base64");
1005
+ instructions.push(
1006
+ new TransactionInstruction({
1007
+ keys: [
1008
+ { pubkey: fromPubkey, isSigner: true, isWritable: true },
1009
+ { pubkey: destinationPubkey, isSigner: false, isWritable: true }
1010
+ ],
1011
+ programId: destinationPubkey,
1012
+ data: dataBuffer
1013
+ })
1014
+ );
1015
+ }
1016
+ }
1017
+ return this.setTransactionDefaults(instructions, fromPubkey);
1018
+ }
1019
+ async createContractCallTransaction(executable) {
1020
+ const userWallet = getWarpWalletAddressFromConfig2(this.config, executable.chain.name);
1021
+ if (!userWallet) throw new Error("WarpSolanaExecutor: createContractCall - user address not set");
1022
+ const action = getWarpActionByIndex(executable.warp, executable.action);
1023
+ if (!action || !("func" in action) || !action.func) throw new Error("WarpSolanaExecutor: Contract action must have a function name");
1024
+ if (!executable.destination) throw new Error("WarpSolanaExecutor: Contract address is required");
1025
+ const programId = this.toPublicKey(executable.destination, "Invalid contract address");
1026
+ const fromPubkey = this.toPublicKey(userWallet, "Invalid user wallet address");
1027
+ const instructions = [];
1028
+ const argsToUse = this.extractContractArgs(executable);
1029
+ const nativeArgs = argsToUse.map((arg) => this.serializer.coreSerializer.stringToNative(arg)[1]);
1030
+ const instructionData = this.buildInstructionData(action, nativeArgs);
1031
+ const accounts = await this.buildInstructionAccounts(action, executable, fromPubkey, programId);
1032
+ await this.ensureATAs(action, accounts, fromPubkey, instructions);
1033
+ instructions.push(new TransactionInstruction({ keys: accounts, programId, data: instructionData }));
1034
+ if (executable.value > 0n) {
1035
+ instructions.push(SystemProgram.transfer({ fromPubkey, toPubkey: programId, lamports: Number(executable.value) }));
1036
+ }
1037
+ return this.setTransactionDefaults(instructions, fromPubkey);
1038
+ }
1039
+ async ensureATAs(action, accounts, fromPubkey, instructions) {
1040
+ if (!action.accounts || !Array.isArray(action.accounts)) return;
1041
+ const createdATAs = /* @__PURE__ */ new Set();
1042
+ for (let idx = 0; idx < action.accounts.length; idx++) {
1043
+ const accountDef = action.accounts[idx];
1044
+ const accountStr = typeof accountDef === "string" ? accountDef : JSON.stringify(accountDef);
1045
+ if (accountStr.includes("{{USER_ATA:")) {
1046
+ const match = accountStr.match(/USER_ATA[:\s]*([^"}\s]+)/);
1047
+ if (match) {
1048
+ const mintAddress = match[1];
1049
+ try {
1050
+ const mintPubkey = new PublicKey3(mintAddress);
1051
+ const expectedAta = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
1052
+ const ataKey = expectedAta.toBase58();
1053
+ if (!createdATAs.has(ataKey)) {
1054
+ createdATAs.add(ataKey);
1055
+ const ataInfo = await this.connection.getAccountInfo(expectedAta);
1056
+ if (!ataInfo) {
1057
+ instructions.push(createAssociatedTokenAccountInstruction(fromPubkey, expectedAta, fromPubkey, mintPubkey));
1058
+ }
1059
+ }
1060
+ } catch {
1061
+ continue;
1062
+ }
1063
+ }
1064
+ }
1065
+ if (accountStr.includes("{{RECEIVER_ATA:")) {
1066
+ const match = accountStr.match(/RECEIVER_ATA[:\s]*([^"}\s:]+)[:\s]*([^"}\s]+)/);
1067
+ if (match) {
1068
+ const mintAddress = match[1];
1069
+ const receiverAddress = match[2];
1070
+ try {
1071
+ const mintPubkey = new PublicKey3(mintAddress);
1072
+ const receiverPubkey = new PublicKey3(receiverAddress);
1073
+ const expectedAta = await getAssociatedTokenAddress(mintPubkey, receiverPubkey);
1074
+ const ataKey = expectedAta.toBase58();
1075
+ if (!createdATAs.has(ataKey)) {
1076
+ createdATAs.add(ataKey);
1077
+ const ataInfo = await this.connection.getAccountInfo(expectedAta);
1078
+ if (!ataInfo) {
1079
+ instructions.push(createAssociatedTokenAccountInstruction(fromPubkey, expectedAta, receiverPubkey, mintPubkey));
1080
+ }
1081
+ }
1082
+ } catch {
1083
+ continue;
1084
+ }
1085
+ }
1086
+ }
1087
+ }
1088
+ }
1089
+ encodeInstructionData(instructionDef, args, funcName) {
1090
+ try {
1091
+ let discriminatorBuffer;
1092
+ if (instructionDef.discriminator) {
1093
+ if (Buffer.isBuffer(instructionDef.discriminator)) {
1094
+ discriminatorBuffer = instructionDef.discriminator;
1095
+ } else if (Array.isArray(instructionDef.discriminator)) {
1096
+ discriminatorBuffer = Buffer.from(instructionDef.discriminator);
1097
+ } else {
1098
+ discriminatorBuffer = Buffer.from(funcName).slice(0, 8);
1099
+ }
1100
+ } else {
1101
+ discriminatorBuffer = Buffer.from(funcName).slice(0, 8);
1102
+ }
1103
+ if (args.length > 0 && instructionDef.args && instructionDef.args.length > 0) {
1104
+ const encodedArgs = this.encodeArgs(args, instructionDef.args);
1105
+ return Buffer.concat([discriminatorBuffer, encodedArgs]);
1106
+ }
1107
+ return discriminatorBuffer;
1108
+ } catch {
1109
+ return this.encodeBasicInstructionData(args, funcName);
1110
+ }
1111
+ }
1112
+ encodeBasicInstructionData(args, funcName) {
1113
+ const funcHash = Buffer.from(funcName).slice(0, 8);
1114
+ const data = Buffer.alloc(8);
1115
+ data.set(funcHash, 0);
1116
+ if (args.length > 0) {
1117
+ const encodedArgs = args.map((arg) => {
1118
+ if (typeof arg === "string") {
1119
+ return Buffer.from(arg, "utf8");
1120
+ } else if (typeof arg === "number" || typeof arg === "bigint") {
1121
+ const num = typeof arg === "bigint" ? Number(arg) : arg;
1122
+ const buf = Buffer.alloc(8);
1123
+ buf.writeBigUInt64LE(BigInt(num), 0);
1124
+ return buf;
1125
+ } else if (Buffer.isBuffer(arg)) {
1126
+ return arg;
1127
+ } else if (arg instanceof Uint8Array) {
1128
+ return Buffer.from(arg);
1129
+ }
1130
+ return Buffer.from(String(arg), "utf8");
1131
+ });
1132
+ return Buffer.concat([data, ...encodedArgs]);
1133
+ }
1134
+ return data;
1135
+ }
1136
+ encodeArgs(args, argDefs) {
1137
+ const buffers = [];
1138
+ for (let i = 0; i < Math.min(args.length, argDefs.length); i++) {
1139
+ const arg = args[i];
1140
+ const def = argDefs[i];
1141
+ if (def.type === "u64" || def.type === "u128") {
1142
+ const num = typeof arg === "bigint" ? arg : BigInt(arg);
1143
+ const size = def.type === "u128" ? 16 : 8;
1144
+ const buf = Buffer.alloc(size);
1145
+ if (size === 16) {
1146
+ buf.writeBigUInt64LE(num & 0xffffffffffffffffn, 0);
1147
+ buf.writeBigUInt64LE(num >> 64n, 8);
1148
+ } else {
1149
+ buf.writeBigUInt64LE(num, 0);
1150
+ }
1151
+ buffers.push(buf);
1152
+ } else if (def.type === "string") {
1153
+ buffers.push(Buffer.from(String(arg), "utf8"));
1154
+ } else if (def.type === "publicKey" || def.type === "pubkey") {
1155
+ try {
1156
+ const pubkey = new PublicKey3(arg);
1157
+ buffers.push(Buffer.from(pubkey.toBuffer()));
1158
+ } catch {
1159
+ buffers.push(Buffer.from(String(arg), "utf8"));
1160
+ }
1161
+ } else {
1162
+ buffers.push(Buffer.from(String(arg), "utf8"));
1163
+ }
1164
+ }
1165
+ return Buffer.concat(buffers);
1166
+ }
1167
+ async buildInstructionAccounts(action, executable, fromPubkey, programId) {
1168
+ const accounts = [];
1169
+ const accountInputs = this.extractAccountInputs(action, executable);
1170
+ if (accountInputs.length > 0) {
1171
+ for (const accountInput of accountInputs) {
1172
+ while (accounts.length < accountInput.index) {
1173
+ accounts.push({ pubkey: fromPubkey, isSigner: true, isWritable: true });
1174
+ }
1175
+ const address = await this.resolveAccountFromInput(accountInput, executable, fromPubkey);
1176
+ const { isSigner, isWritable } = this.determineAccountFlags(accountInput.input, address, fromPubkey);
1177
+ accounts.push({ pubkey: address, isSigner, isWritable });
1178
+ }
1179
+ return accounts;
1180
+ }
1181
+ if (!action.accounts || !Array.isArray(action.accounts)) return accounts;
1182
+ for (let idx = 0; idx < action.accounts.length; idx++) {
1183
+ const accountDef = action.accounts[idx];
1184
+ let address = this.extractAccountAddress(accountDef);
1185
+ if (address === "[object Object]" || typeof accountDef === "string" && accountDef === "[object Object]") {
1186
+ address = fromPubkey.toBase58();
1187
+ } else if (!address || address.length === 0) {
1188
+ throw new Error(`Invalid account definition at index ${idx}: ${JSON.stringify(accountDef)}`);
1189
+ }
1190
+ if (address === "{{USER_WALLET}}" || typeof address === "string" && address.includes("{{USER_WALLET}}")) {
1191
+ address = fromPubkey.toBase58();
1192
+ } else if (typeof address === "string" && address.includes("{{")) {
1193
+ const originalAddress = address;
1194
+ let maxIterations = 10;
1195
+ while (address.includes("{{") && maxIterations-- > 0) {
1196
+ const beforeInterpolation = address;
1197
+ address = this.interpolateAccountAddress(address, executable.resolvedInputs);
1198
+ if (address === beforeInterpolation) break;
1199
+ }
1200
+ if (!address || address.includes("{{") && !address.startsWith("{{USER_ATA:") && !address.startsWith("{{RECEIVER_ATA:")) {
1201
+ throw new Error(`Failed to interpolate account address at index ${idx}: ${originalAddress} -> ${address}. ResolvedInputs: ${JSON.stringify(executable.resolvedInputs.map((r) => ({ as: r.input?.as, value: r.value })))}`);
1202
+ }
1203
+ }
1204
+ const pubkey = await this.resolveAccountPubkey(address, fromPubkey);
1205
+ const { isSigner, isWritable } = this.determineAccountFlags(accountDef, pubkey, fromPubkey);
1206
+ accounts.push({ pubkey, isSigner, isWritable });
1207
+ }
1208
+ return accounts;
1209
+ }
1210
+ extractAccountInputs(action, executable) {
1211
+ if (!action.inputs || !Array.isArray(action.inputs)) return [];
1212
+ const accountInputs = [];
1213
+ for (const input of action.inputs) {
1214
+ if (input.position && typeof input.position === "string" && input.position.startsWith("account:")) {
1215
+ const index = parseInt(input.position.split(":")[1] || "0", 10);
1216
+ accountInputs.push({ input, index });
1217
+ }
1218
+ }
1219
+ return accountInputs.sort((a, b) => a.index - b.index);
1220
+ }
1221
+ async resolveAccountFromInput(accountInput, executable, fromPubkey) {
1222
+ const resolved = executable.resolvedInputs.find((r) => r.input === accountInput.input || r.input?.as === accountInput.input.as);
1223
+ if (!resolved) {
1224
+ throw new Error(`Account input at index ${accountInput.index} not resolved: ${accountInput.input.as || accountInput.input.name}`);
1225
+ }
1226
+ let address = resolved.value;
1227
+ if (typeof address === "string" && address.includes(":")) {
1228
+ address = address.split(":")[1];
1229
+ }
1230
+ if (!address || typeof address !== "string") {
1231
+ throw new Error(`Invalid address for account input at index ${accountInput.index}: ${accountInput.input.as || accountInput.input.name}`);
1232
+ }
1233
+ if (accountInput.input.as === "USER_WALLET") {
1234
+ return fromPubkey;
1235
+ }
1236
+ if (accountInput.input.as?.startsWith("USER_ATA:") || accountInput.input.as?.startsWith("RECEIVER_ATA:")) {
1237
+ return await this.resolveAccountPubkey(`{{${accountInput.input.as}}}`, fromPubkey);
1238
+ }
1239
+ return new PublicKey3(address);
1240
+ }
1241
+ interpolateAccountAddress(address, resolvedInputs) {
1242
+ if (!address.includes("{{")) return address;
1243
+ for (const resolved of resolvedInputs) {
1244
+ if (!resolved.input?.as) continue;
1245
+ const placeholder = `{{${resolved.input.as.toUpperCase()}}}`;
1246
+ if (address === placeholder || address.includes(placeholder)) {
1247
+ let value = resolved.value;
1248
+ if (typeof value === "string" && value.includes(":")) {
1249
+ value = value.split(":")[1];
1250
+ }
1251
+ if (value) {
1252
+ return address.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), String(value));
1253
+ }
1254
+ }
1255
+ }
1256
+ for (const resolved of resolvedInputs) {
1257
+ if (!resolved.input?.name) continue;
1258
+ const placeholder = `{{${resolved.input.name.toUpperCase().replace(/\s+/g, "_")}}}`;
1259
+ if (address === placeholder || address.includes(placeholder)) {
1260
+ let value = resolved.value;
1261
+ if (typeof value === "string" && value.includes(":")) {
1262
+ value = value.split(":")[1];
1263
+ }
1264
+ if (value) {
1265
+ return address.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), String(value));
1266
+ }
1267
+ }
1268
+ }
1269
+ return address;
1270
+ }
1271
+ async createTokenTransferTransaction(executable, userWallet, destinationPubkey) {
1272
+ if (executable.transfers.length === 0) throw new Error("WarpSolanaExecutor: No transfers provided");
1273
+ if (!this.chain.nativeToken?.identifier) throw new Error("WarpSolanaExecutor: No native token defined for this chain");
1274
+ const nativeId = this.chain.nativeToken.identifier;
1275
+ const nativeTokenTransfers = executable.transfers.filter((t) => t.identifier === nativeId || t.identifier === WarpSolanaConstants.NativeToken.Identifier);
1276
+ const splTokenTransfers = executable.transfers.filter((t) => t.identifier !== nativeId && t.identifier !== WarpSolanaConstants.NativeToken.Identifier);
1277
+ if (nativeTokenTransfers.length === 1 && splTokenTransfers.length === 0) {
1278
+ const transfer = nativeTokenTransfers[0];
1279
+ if (transfer.amount <= 0n) throw new Error("WarpSolanaExecutor: Native token transfer amount must be positive");
1280
+ const fromPubkey = new PublicKey3(userWallet);
1281
+ return this.setTransactionDefaults([SystemProgram.transfer({ fromPubkey, toPubkey: destinationPubkey, lamports: Number(transfer.amount) })], fromPubkey);
1282
+ }
1283
+ if (nativeTokenTransfers.length === 0 && splTokenTransfers.length === 1) {
1284
+ return this.createSingleTokenTransfer(executable, splTokenTransfers[0], userWallet, destinationPubkey);
1285
+ }
1286
+ if (executable.transfers.length > 1) throw new Error("WarpSolanaExecutor: Multiple token transfers not yet supported");
1287
+ throw new Error("WarpSolanaExecutor: Invalid transfer configuration");
1288
+ }
1289
+ async createSingleTokenTransfer(executable, transfer, userWallet, destinationPubkey) {
1290
+ const mintAddress = new PublicKey3(transfer.identifier);
1291
+ const fromPubkey = new PublicKey3(userWallet);
1292
+ const sourceTokenAccount = await getAssociatedTokenAddress(mintAddress, fromPubkey);
1293
+ const destinationTokenAccount = await getAssociatedTokenAddress(mintAddress, destinationPubkey);
1294
+ if (!await this.connection.getAccountInfo(sourceTokenAccount)) {
1295
+ throw new Error("WarpSolanaExecutor: Source token account does not exist");
1296
+ }
1297
+ const instructions = [];
1298
+ if (!await this.connection.getAccountInfo(destinationTokenAccount)) {
1299
+ instructions.push(createAssociatedTokenAccountInstruction(fromPubkey, destinationTokenAccount, destinationPubkey, mintAddress));
1300
+ }
1301
+ instructions.push(createTransferInstruction(sourceTokenAccount, destinationTokenAccount, fromPubkey, Number(transfer.amount)));
1302
+ return this.setTransactionDefaults(instructions, fromPubkey);
1303
+ }
1304
+ async executeQuery(executable) {
1305
+ const action = getWarpActionByIndex(executable.warp, executable.action);
1306
+ if (action.type !== "query") throw new Error(`WarpSolanaExecutor: Invalid action type for executeQuery: ${action.type}`);
1307
+ if (!action.func) throw new Error("WarpSolanaExecutor: Query action must have a function name");
1308
+ if (!executable.destination) throw new Error("WarpSolanaExecutor: Query address is required");
1309
+ const queryAddress = new PublicKey3(executable.destination);
1310
+ const nativeArgs = executable.args.map((arg) => this.serializer.coreSerializer.stringToNative(arg)[1]);
1311
+ let decodedResult = [];
1312
+ let isSuccess = true;
1313
+ if (action.func === "getAccount" || action.func === "getAccountInfo") {
1314
+ const accountInfo = await this.connection.getAccountInfo(queryAddress);
1315
+ if (!accountInfo) {
1316
+ throw new Error("Account not found");
1317
+ }
1318
+ decodedResult = [
1319
+ accountInfo.lamports,
1320
+ accountInfo.owner.toBase58(),
1321
+ accountInfo.executable,
1322
+ accountInfo.rentEpoch,
1323
+ accountInfo.data.toString("base64")
1324
+ ];
1325
+ } else if (action.func === "getBalance") {
1326
+ const balance = await this.connection.getBalance(queryAddress);
1327
+ decodedResult = [balance.toString()];
1328
+ } else if (action.func === "getProgramAccounts") {
1329
+ const accounts = await this.connection.getProgramAccounts(queryAddress);
1330
+ decodedResult = accounts.map((acc) => ({
1331
+ pubkey: acc.pubkey.toBase58(),
1332
+ account: {
1333
+ lamports: acc.account.lamports,
1334
+ owner: acc.account.owner.toBase58(),
1335
+ data: acc.account.data.toString("base64")
1336
+ }
1337
+ }));
1338
+ } else {
1339
+ const accountInfo = await this.connection.getAccountInfo(queryAddress);
1340
+ if (!accountInfo) {
1341
+ throw new Error("Account not found");
1342
+ }
1343
+ decodedResult = [accountInfo.data.toString("base64")];
1344
+ }
1345
+ const { values, output } = await this.output.extractQueryOutput(executable.warp, decodedResult, executable.action, executable.resolvedInputs);
1346
+ const next = getNextInfo(this.config, [], executable.warp, executable.action, output);
1347
+ const destinationInput = executable.resolvedInputs.find((i) => i.input.position === "receiver" || i.input.position === "destination");
1348
+ const destination = destinationInput?.value || executable.destination;
1349
+ const resolvedInputs = extractResolvedInputValues2(executable.resolvedInputs);
1350
+ return {
1351
+ status: isSuccess ? "success" : "error",
1352
+ warp: executable.warp,
1353
+ action: executable.action,
1354
+ user: getWarpWalletAddressFromConfig2(this.config, executable.chain.name),
1355
+ txHash: null,
1356
+ tx: null,
1357
+ next,
1358
+ values,
1359
+ output: { ...output, _DATA: decodedResult },
1360
+ messages: applyOutputToMessages(executable.warp, output, this.config),
1361
+ destination,
1362
+ resolvedInputs
1363
+ };
1364
+ }
1365
+ async verifyMessage(message, signature) {
1366
+ try {
1367
+ const messageBytes = new TextEncoder().encode(message);
1368
+ const signatureBytes = Buffer.from(signature, "base64");
1369
+ return "";
1370
+ } catch (error) {
1371
+ throw new Error(`Failed to verify message: ${error}`);
1372
+ }
1373
+ }
1374
+ async setTransactionDefaults(instructions, fromPubkey) {
1375
+ const { blockhash } = await this.connection.getLatestBlockhash("confirmed");
1376
+ const allInstructions = this.addComputeBudgetInstructions(instructions);
1377
+ const accountMetaMap = this.buildAccountMetaMap(allInstructions, fromPubkey);
1378
+ const { signedAccounts, unsignedAccounts } = this.sortAccounts(accountMetaMap);
1379
+ const { staticAccountKeys, accountIndexMap } = this.buildAccountIndexMap(signedAccounts, unsignedAccounts);
1380
+ const compiledInstructions = this.compileInstructions(allInstructions, accountIndexMap);
1381
+ const messageV0 = this.buildMessageV0(blockhash, signedAccounts, unsignedAccounts, accountMetaMap, staticAccountKeys, compiledInstructions);
1382
+ const versionedTx = new VersionedTransaction(messageV0);
1383
+ if (versionedTx.version !== 0) {
1384
+ throw new Error(`Expected VersionedTransaction v0, got version: ${versionedTx.version}`);
1385
+ }
1386
+ return versionedTx;
1387
+ }
1388
+ toPublicKey(address, errorMsg) {
1389
+ try {
1390
+ return new PublicKey3(address);
1391
+ } catch {
1392
+ throw new Error(`WarpSolanaExecutor: ${errorMsg}`);
1393
+ }
1394
+ }
1395
+ extractContractArgs(executable) {
1396
+ if (executable.args.length > 0) return executable.args;
1397
+ if (executable.resolvedInputs.length === 0) return [];
1398
+ const argInputs = executable.resolvedInputs.filter((ri) => ri.input.position?.toString().startsWith("arg:")).map((ri) => {
1399
+ const index = Math.max(0, parseInt(ri.input.position.toString().split(":")[1] || "0", 10) - 1);
1400
+ return { index, value: ri.value };
1401
+ }).sort((a, b) => a.index - b.index);
1402
+ const maxIndex = Math.max(...argInputs.map((a) => a.index), -1);
1403
+ if (maxIndex < 0) return [];
1404
+ const args = new Array(maxIndex + 1).fill(null);
1405
+ argInputs.forEach(({ index, value }) => {
1406
+ if (value) args[index] = value;
1407
+ });
1408
+ return args.filter((arg) => arg !== null && arg !== void 0);
1409
+ }
1410
+ buildInstructionData(action, nativeArgs) {
1411
+ if (!action.abi || typeof action.abi !== "string") {
1412
+ return this.encodeBasicInstructionData(nativeArgs, action.func);
1413
+ }
1414
+ try {
1415
+ const abi = JSON.parse(action.abi);
1416
+ if (abi.instructions && abi.instructions[action.func]) {
1417
+ return this.encodeInstructionData(abi.instructions[action.func], nativeArgs, action.func);
1418
+ }
1419
+ } catch {
1420
+ }
1421
+ return this.encodeBasicInstructionData(nativeArgs, action.func);
1422
+ }
1423
+ extractAccountAddress(accountDef) {
1424
+ if (typeof accountDef === "string") return accountDef;
1425
+ if (!accountDef || typeof accountDef !== "object") return void 0;
1426
+ const str = JSON.stringify(accountDef);
1427
+ if (str.includes("USER_WALLET") || str.includes("{{USER_WALLET}}")) return "{{USER_WALLET}}";
1428
+ if (str.includes("RECEIVER_ADDRESS") || str.includes("{{RECEIVER_ADDRESS}}")) return "{{RECEIVER_ADDRESS}}";
1429
+ if (str.includes("USER_ATA")) {
1430
+ const match = str.match(/USER_ATA[:\s]*([^"}\s]+)/);
1431
+ if (match) return `{{USER_ATA:${match[1]}}}`;
1432
+ }
1433
+ const addrValue = accountDef.address || accountDef.pubkey || accountDef.value;
1434
+ if (typeof addrValue === "string") return addrValue;
1435
+ if (addrValue?.toBase58) return addrValue.toBase58();
1436
+ if (addrValue?.identifier) return addrValue.identifier;
1437
+ if (addrValue?.value) return addrValue.value;
1438
+ const keys = Object.keys(accountDef);
1439
+ if (keys.length === 1 && typeof accountDef[keys[0]] === "string") return accountDef[keys[0]];
1440
+ return void 0;
1441
+ }
1442
+ async resolveAccountPubkey(address, fromPubkey) {
1443
+ if (address.includes("{{USER_WALLET}}") || address === fromPubkey.toBase58()) {
1444
+ return fromPubkey;
1445
+ }
1446
+ if (address.startsWith("{{USER_ATA:") && address.endsWith("}}")) {
1447
+ const mintAddress = address.slice(11, -2);
1448
+ if (!mintAddress || mintAddress.includes("{{")) {
1449
+ throw new Error(`Invalid USER_ATA placeholder: ${address}. Mint address must be resolved first.`);
1450
+ }
1451
+ const mintPubkey = new PublicKey3(mintAddress);
1452
+ return await getAssociatedTokenAddress(mintPubkey, fromPubkey);
1453
+ }
1454
+ if (address.startsWith("{{RECEIVER_ATA:") && address.endsWith("}}")) {
1455
+ const content = address.slice(15, -2);
1456
+ const parts = content.split(":");
1457
+ if (parts.length === 2) {
1458
+ let mintAddress = parts[0];
1459
+ let receiverAddress = parts[1];
1460
+ if (mintAddress.includes("{{") || receiverAddress.includes("{{")) {
1461
+ throw new Error(`Invalid RECEIVER_ATA placeholder: ${address}. Mint and receiver addresses must be resolved first.`);
1462
+ }
1463
+ if (mintAddress.includes(":")) mintAddress = mintAddress.split(":")[1];
1464
+ if (receiverAddress.includes(":")) receiverAddress = receiverAddress.split(":")[1];
1465
+ const mintPubkey = new PublicKey3(mintAddress);
1466
+ const receiverPubkey = new PublicKey3(receiverAddress);
1467
+ return await getAssociatedTokenAddress(mintPubkey, receiverPubkey);
1468
+ }
1469
+ }
1470
+ return new PublicKey3(address);
1471
+ }
1472
+ determineAccountFlags(accountDef, pubkey, fromPubkey) {
1473
+ const accountMeta = typeof accountDef === "object" ? accountDef : {};
1474
+ if (pubkey.equals(fromPubkey)) {
1475
+ return { isSigner: true, isWritable: true };
1476
+ }
1477
+ const isSigner = accountMeta.signer === true;
1478
+ const isWritable = typeof accountDef === "object" && accountMeta.writable !== void 0 ? accountMeta.writable !== false : true;
1479
+ return { isSigner, isWritable };
1480
+ }
1481
+ addComputeBudgetInstructions(instructions) {
1482
+ const hasTokenTransfer = instructions.some((ix) => ix.programId.toBase58() === WarpSolanaConstants.Programs.TokenProgram);
1483
+ const computeUnits = hasTokenTransfer ? WarpSolanaConstants.ComputeUnitLimit.TokenTransfer : WarpSolanaConstants.ComputeUnitLimit.Default;
1484
+ const computeUnitLimitIx = ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits });
1485
+ const computeUnitPriceIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: WarpSolanaConstants.PriorityFee.Default });
1486
+ return [computeUnitLimitIx, computeUnitPriceIx, ...instructions];
1487
+ }
1488
+ buildAccountMetaMap(instructions, fromPubkey) {
1489
+ const accountMetaMap = /* @__PURE__ */ new Map();
1490
+ if (fromPubkey) {
1491
+ accountMetaMap.set(fromPubkey.toBase58(), { pubkey: fromPubkey, isSigner: true, isWritable: true });
1492
+ }
1493
+ for (const ix of instructions) {
1494
+ const programIdStr = ix.programId.toBase58();
1495
+ if (!accountMetaMap.has(programIdStr)) {
1496
+ accountMetaMap.set(programIdStr, { pubkey: ix.programId, isSigner: false, isWritable: false });
1497
+ }
1498
+ for (const key of ix.keys) {
1499
+ const keyStr = key.pubkey.toBase58();
1500
+ const existing = accountMetaMap.get(keyStr);
1501
+ if (existing) {
1502
+ accountMetaMap.set(keyStr, {
1503
+ pubkey: key.pubkey,
1504
+ isSigner: existing.isSigner || key.isSigner,
1505
+ isWritable: existing.isWritable || key.isWritable
1506
+ });
1507
+ } else {
1508
+ accountMetaMap.set(keyStr, {
1509
+ pubkey: key.pubkey,
1510
+ isSigner: key.isSigner,
1511
+ isWritable: key.isWritable
1512
+ });
1513
+ }
1514
+ }
1515
+ }
1516
+ return accountMetaMap;
1517
+ }
1518
+ sortAccounts(accountMetaMap) {
1519
+ const signedAccounts = [];
1520
+ const unsignedAccounts = [];
1521
+ for (const meta of accountMetaMap.values()) {
1522
+ ;
1523
+ (meta.isSigner ? signedAccounts : unsignedAccounts).push(meta.pubkey);
1524
+ }
1525
+ const sortByWritable = (a, b) => (accountMetaMap.get(a.toBase58()).isWritable ? 0 : 1) - (accountMetaMap.get(b.toBase58()).isWritable ? 0 : 1);
1526
+ signedAccounts.sort(sortByWritable);
1527
+ unsignedAccounts.sort(sortByWritable);
1528
+ return { signedAccounts, unsignedAccounts };
1529
+ }
1530
+ buildAccountIndexMap(signedAccounts, unsignedAccounts) {
1531
+ const staticAccountKeys = [...signedAccounts, ...unsignedAccounts];
1532
+ const accountIndexMap = /* @__PURE__ */ new Map();
1533
+ staticAccountKeys.forEach((key, index) => {
1534
+ accountIndexMap.set(key.toBase58(), index);
1535
+ });
1536
+ return { staticAccountKeys, accountIndexMap };
1537
+ }
1538
+ compileInstructions(instructions, accountIndexMap) {
1539
+ return instructions.map((ix) => {
1540
+ const programIdIndex = accountIndexMap.get(ix.programId.toBase58());
1541
+ const accountKeyIndexes = ix.keys.map((key) => accountIndexMap.get(key.pubkey.toBase58()));
1542
+ return {
1543
+ programIdIndex,
1544
+ accountKeyIndexes,
1545
+ data: Uint8Array.from(ix.data)
1546
+ };
1547
+ });
1548
+ }
1549
+ buildMessageV0(blockhash, signedAccounts, unsignedAccounts, accountMetaMap, staticAccountKeys, compiledInstructions) {
1550
+ const getWritable = (key) => accountMetaMap.get(key.toBase58()).isWritable;
1551
+ return new MessageV0({
1552
+ header: {
1553
+ numRequiredSignatures: signedAccounts.length,
1554
+ numReadonlySignedAccounts: signedAccounts.filter((k) => !getWritable(k)).length,
1555
+ numReadonlyUnsignedAccounts: unsignedAccounts.filter((k) => !getWritable(k)).length
1556
+ },
1557
+ staticAccountKeys,
1558
+ recentBlockhash: blockhash,
1559
+ compiledInstructions,
1560
+ addressTableLookups: []
1561
+ });
1562
+ }
1563
+ };
1564
+
1565
+ // src/WarpSolanaExplorer.ts
1566
+ var WarpSolanaExplorer = class {
1567
+ constructor(chain, config) {
1568
+ this.chain = chain;
1569
+ this.config = config;
1570
+ }
1571
+ getExplorers() {
1572
+ const explorers = SolanaExplorerNames[this.config.env];
1573
+ if (!explorers) {
1574
+ return ["solscan_mainnet" /* SolscanMainnet */];
1575
+ }
1576
+ return explorers;
1577
+ }
1578
+ getPrimaryExplorer() {
1579
+ const explorers = this.getExplorers();
1580
+ return explorers[0];
1581
+ }
1582
+ getExplorerUrlByName(explorer) {
1583
+ const userPreference = this.config.preferences?.explorers?.[this.chain.name];
1584
+ if (userPreference && !explorer) {
1585
+ const url2 = SolanaExplorerUrls[userPreference];
1586
+ if (url2) return url2;
1587
+ }
1588
+ if (explorer) {
1589
+ const url2 = SolanaExplorerUrls[explorer];
1590
+ if (url2) return url2;
1591
+ }
1592
+ const primaryExplorer = this.getPrimaryExplorer();
1593
+ const url = SolanaExplorerUrls[primaryExplorer];
1594
+ return url || SolanaExplorerUrls[primaryExplorer];
1595
+ }
1596
+ getAccountUrl(address, explorer) {
1597
+ const baseUrl = this.getExplorerUrlByName(explorer);
1598
+ if (baseUrl.includes("?")) {
1599
+ const cluster2 = this.config.env === "mainnet" ? "" : `&cluster=${this.config.env}`;
1600
+ return `${baseUrl}/account/${address}${cluster2}`;
1601
+ }
1602
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1603
+ return `${baseUrl}/account/${address}${cluster}`;
1604
+ }
1605
+ getTransactionUrl(hash, explorer) {
1606
+ const baseUrl = this.getExplorerUrlByName(explorer);
1607
+ if (baseUrl.includes("?")) {
1608
+ const cluster2 = this.config.env === "mainnet" ? "" : `&cluster=${this.config.env}`;
1609
+ return `${baseUrl}/tx/${hash}${cluster2}`;
1610
+ }
1611
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1612
+ return `${baseUrl}/tx/${hash}${cluster}`;
1613
+ }
1614
+ getBlockUrl(blockNumber, explorer) {
1615
+ const baseUrl = this.getExplorerUrlByName(explorer);
1616
+ if (baseUrl.includes("?")) {
1617
+ const cluster2 = this.config.env === "mainnet" ? "" : `&cluster=${this.config.env}`;
1618
+ return `${baseUrl}/block/${blockNumber}${cluster2}`;
1619
+ }
1620
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1621
+ return `${baseUrl}/block/${blockNumber}${cluster}`;
1622
+ }
1623
+ getAssetUrl(identifier, explorer) {
1624
+ const baseUrl = this.getExplorerUrlByName(explorer);
1625
+ if (baseUrl.includes("?")) {
1626
+ const cluster2 = this.config.env === "mainnet" ? "" : `&cluster=${this.config.env}`;
1627
+ return `${baseUrl}/token/${identifier}${cluster2}`;
1628
+ }
1629
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1630
+ return `${baseUrl}/token/${identifier}${cluster}`;
1631
+ }
1632
+ getContractUrl(address, explorer) {
1633
+ const baseUrl = this.getExplorerUrlByName(explorer);
1634
+ if (baseUrl.includes("?")) {
1635
+ const cluster2 = this.config.env === "mainnet" ? "" : `&cluster=${this.config.env}`;
1636
+ return `${baseUrl}/account/${address}${cluster2}`;
1637
+ }
1638
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1639
+ return `${baseUrl}/account/${address}${cluster}`;
1640
+ }
1641
+ getAllExplorers() {
1642
+ return this.getExplorers();
1643
+ }
1644
+ getExplorerByName(name) {
1645
+ const explorers = this.getExplorers();
1646
+ return explorers.find((explorer) => explorer.toLowerCase() === name.toLowerCase());
1647
+ }
1648
+ getAccountUrls(address) {
1649
+ const explorers = this.getAllExplorers();
1650
+ const urls = {};
1651
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1652
+ explorers.forEach((explorer) => {
1653
+ const url = SolanaExplorerUrls[explorer];
1654
+ if (url) {
1655
+ urls[explorer] = `${url}/account/${address}${cluster}`;
1656
+ }
1657
+ });
1658
+ return urls;
1659
+ }
1660
+ getTransactionUrls(hash) {
1661
+ const explorers = this.getAllExplorers();
1662
+ const urls = {};
1663
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1664
+ explorers.forEach((explorer) => {
1665
+ const url = SolanaExplorerUrls[explorer];
1666
+ if (url) {
1667
+ urls[explorer] = `${url}/tx/${hash}${cluster}`;
1668
+ }
1669
+ });
1670
+ return urls;
1671
+ }
1672
+ getAssetUrls(identifier) {
1673
+ const explorers = this.getAllExplorers();
1674
+ const urls = {};
1675
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1676
+ explorers.forEach((explorer) => {
1677
+ const url = SolanaExplorerUrls[explorer];
1678
+ if (url) {
1679
+ urls[explorer] = `${url}/token/${identifier}${cluster}`;
1680
+ }
1681
+ });
1682
+ return urls;
1683
+ }
1684
+ getContractUrls(address) {
1685
+ const explorers = this.getAllExplorers();
1686
+ const urls = {};
1687
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1688
+ explorers.forEach((explorer) => {
1689
+ const url = SolanaExplorerUrls[explorer];
1690
+ if (url) {
1691
+ urls[explorer] = `${url}/account/${address}${cluster}`;
1692
+ }
1693
+ });
1694
+ return urls;
1695
+ }
1696
+ getBlockUrls(blockNumber) {
1697
+ const explorers = this.getAllExplorers();
1698
+ const urls = {};
1699
+ const cluster = this.config.env === "mainnet" ? "" : `?cluster=${this.config.env}`;
1700
+ explorers.forEach((explorer) => {
1701
+ const url = SolanaExplorerUrls[explorer];
1702
+ if (url) {
1703
+ urls[explorer] = `${url}/block/${blockNumber}${cluster}`;
1704
+ }
1705
+ });
1706
+ return urls;
1707
+ }
1708
+ };
1709
+
1710
+ // src/WarpSolanaWallet.ts
1711
+ import { createKeyPairSignerFromBytes } from "@solana/kit";
1712
+ import { Connection as Connection4, Transaction as Transaction3, VersionedTransaction as VersionedTransaction4 } from "@solana/web3.js";
1713
+ import {
1714
+ getProviderConfig as getProviderConfig4,
1715
+ initializeWalletCache
1716
+ } from "@joai/warps";
1717
+ import { registerExactSvmScheme } from "@x402/svm/exact/client";
1718
+
1719
+ // src/providers/MnemonicWalletProvider.ts
1720
+ import * as bip39 from "@scure/bip39";
1721
+ import { wordlist } from "@scure/bip39/wordlists/english.js";
1722
+ import { Keypair, Transaction, VersionedTransaction as VersionedTransaction2 } from "@solana/web3.js";
1723
+ import {
1724
+ getWarpWalletAddressFromConfig as getWarpWalletAddressFromConfig3,
1725
+ getWarpWalletMnemonicFromConfig,
1726
+ getWarpWalletPrivateKeyFromConfig,
1727
+ normalizeAndValidateMnemonic,
1728
+ normalizeMnemonic,
1729
+ setWarpWalletInConfig,
1730
+ validateMnemonicLength
1731
+ } from "@joai/warps";
1732
+ import bs582 from "bs58";
1733
+ var _MnemonicWalletProvider = class _MnemonicWalletProvider {
1734
+ constructor(config, chain) {
1735
+ this.config = config;
1736
+ this.chain = chain;
1737
+ this.keypair = null;
1738
+ }
1739
+ async getAddress() {
1740
+ const address = getWarpWalletAddressFromConfig3(this.config, this.chain.name);
1741
+ if (address) return address;
1742
+ try {
1743
+ const keypair = this.getKeypair();
1744
+ return keypair.publicKey.toBase58();
1745
+ } catch {
1746
+ return null;
1747
+ }
1748
+ }
1749
+ async getPublicKey() {
1750
+ try {
1751
+ const keypair = this.getKeypair();
1752
+ return keypair.publicKey.toBase58();
1753
+ } catch {
1754
+ return null;
1755
+ }
1756
+ }
1757
+ async signTransaction(tx) {
1758
+ const keypair = this.getKeypair();
1759
+ if (tx instanceof VersionedTransaction2) {
1760
+ tx.sign([keypair]);
1761
+ return tx;
1762
+ }
1763
+ if (tx instanceof Transaction) {
1764
+ tx.sign(keypair);
1765
+ return tx;
1766
+ }
1767
+ if (tx.transaction) {
1768
+ if (tx.transaction instanceof Transaction) {
1769
+ tx.transaction.sign(keypair);
1770
+ return { ...tx, transaction: tx.transaction.serialize() };
1771
+ }
1772
+ if (typeof tx.transaction === "object") {
1773
+ try {
1774
+ const transaction = Transaction.from(tx.transaction);
1775
+ transaction.sign(keypair);
1776
+ return { ...tx, transaction: transaction.serialize(), signature: transaction.signature };
1777
+ } catch {
1778
+ throw new Error("Invalid transaction format");
1779
+ }
1780
+ }
1781
+ }
1782
+ throw new Error("Invalid transaction format");
1783
+ }
1784
+ async signMessage(message) {
1785
+ const keypair = this.getKeypair();
1786
+ const messageBytes = new TextEncoder().encode(message);
1787
+ const nacl = await import("tweetnacl");
1788
+ const secretKey = keypair.secretKey;
1789
+ if (secretKey.length !== 64) {
1790
+ throw new Error(`Invalid secret key length: expected 64, got ${secretKey.length}`);
1791
+ }
1792
+ const privateKeySlice = secretKey.slice(0, 32);
1793
+ const privateKeyBytes = new Uint8Array(privateKeySlice);
1794
+ if (privateKeyBytes.length !== 32) {
1795
+ throw new Error(`Invalid private key length: expected 32, got ${privateKeyBytes.length}`);
1796
+ }
1797
+ const signature = nacl.sign.detached(messageBytes, privateKeyBytes);
1798
+ return bs582.encode(signature);
1799
+ }
1800
+ getKeypairInstance() {
1801
+ return this.getKeypair();
1802
+ }
1803
+ async importFromMnemonic(mnemonic) {
1804
+ const trimmedMnemonic = normalizeAndValidateMnemonic(mnemonic);
1805
+ const seed = bip39.mnemonicToSeedSync(trimmedMnemonic);
1806
+ const keypair = Keypair.fromSeed(seed.slice(0, 32));
1807
+ const walletDetails = {
1808
+ provider: _MnemonicWalletProvider.PROVIDER_NAME,
1809
+ address: keypair.publicKey.toBase58(),
1810
+ privateKey: bs582.encode(keypair.secretKey),
1811
+ mnemonic: trimmedMnemonic
1812
+ };
1813
+ setWarpWalletInConfig(this.config, this.chain.name, walletDetails);
1814
+ return walletDetails;
1815
+ }
1816
+ async importFromPrivateKey(privateKey) {
1817
+ const keypair = Keypair.fromSecretKey(bs582.decode(privateKey));
1818
+ const walletDetails = {
1819
+ provider: _MnemonicWalletProvider.PROVIDER_NAME,
1820
+ address: keypair.publicKey.toBase58(),
1821
+ privateKey: bs582.encode(keypair.secretKey),
1822
+ mnemonic: null
1823
+ };
1824
+ setWarpWalletInConfig(this.config, this.chain.name, walletDetails);
1825
+ return walletDetails;
1826
+ }
1827
+ async export() {
1828
+ const keypair = this.getKeypair();
1829
+ const mnemonic = getWarpWalletMnemonicFromConfig(this.config, this.chain.name);
1830
+ const privateKey = getWarpWalletPrivateKeyFromConfig(this.config, this.chain.name);
1831
+ return {
1832
+ provider: _MnemonicWalletProvider.PROVIDER_NAME,
1833
+ address: keypair.publicKey.toBase58(),
1834
+ privateKey: privateKey || null,
1835
+ mnemonic: mnemonic || null
1836
+ };
1837
+ }
1838
+ async generate() {
1839
+ const mnemonicRaw = bip39.generateMnemonic(wordlist, 256);
1840
+ const mnemonic = normalizeMnemonic(mnemonicRaw);
1841
+ validateMnemonicLength(mnemonic);
1842
+ const seed = bip39.mnemonicToSeedSync(mnemonic);
1843
+ const keypair = Keypair.fromSeed(seed.slice(0, 32));
1844
+ return {
1845
+ provider: _MnemonicWalletProvider.PROVIDER_NAME,
1846
+ address: keypair.publicKey.toBase58(),
1847
+ privateKey: null,
1848
+ mnemonic
1849
+ };
1850
+ }
1851
+ getKeypair() {
1852
+ if (this.keypair) return this.keypair;
1853
+ const mnemonic = getWarpWalletMnemonicFromConfig(this.config, this.chain.name);
1854
+ if (!mnemonic) throw new Error("No mnemonic provided");
1855
+ const seed = bip39.mnemonicToSeedSync(mnemonic);
1856
+ this.keypair = Keypair.fromSeed(seed.slice(0, 32));
1857
+ return this.keypair;
1858
+ }
1859
+ };
1860
+ _MnemonicWalletProvider.PROVIDER_NAME = "mnemonic";
1861
+ var MnemonicWalletProvider = _MnemonicWalletProvider;
1862
+
1863
+ // src/providers/PrivateKeyWalletProvider.ts
1864
+ import { Keypair as Keypair2, Transaction as Transaction2, VersionedTransaction as VersionedTransaction3 } from "@solana/web3.js";
1865
+ import {
1866
+ getWarpWalletAddressFromConfig as getWarpWalletAddressFromConfig4,
1867
+ getWarpWalletMnemonicFromConfig as getWarpWalletMnemonicFromConfig2,
1868
+ getWarpWalletPrivateKeyFromConfig as getWarpWalletPrivateKeyFromConfig2,
1869
+ setWarpWalletInConfig as setWarpWalletInConfig2
1870
+ } from "@joai/warps";
1871
+ import bs583 from "bs58";
1872
+ var _PrivateKeyWalletProvider = class _PrivateKeyWalletProvider {
1873
+ constructor(config, chain) {
1874
+ this.config = config;
1875
+ this.chain = chain;
1876
+ this.keypair = null;
1877
+ }
1878
+ async getAddress() {
1879
+ const address = getWarpWalletAddressFromConfig4(this.config, this.chain.name);
1880
+ if (address) return address;
1881
+ try {
1882
+ const keypair = this.getKeypair();
1883
+ return keypair.publicKey.toBase58();
1884
+ } catch {
1885
+ return null;
1886
+ }
1887
+ }
1888
+ async getPublicKey() {
1889
+ try {
1890
+ const keypair = this.getKeypair();
1891
+ return keypair.publicKey.toBase58();
1892
+ } catch {
1893
+ return null;
1894
+ }
1895
+ }
1896
+ async signTransaction(tx) {
1897
+ const keypair = this.getKeypair();
1898
+ if (tx instanceof VersionedTransaction3) {
1899
+ tx.sign([keypair]);
1900
+ return tx;
1901
+ }
1902
+ if (tx instanceof Transaction2) {
1903
+ tx.sign(keypair);
1904
+ return tx;
1905
+ }
1906
+ if (tx.transaction) {
1907
+ if (tx.transaction instanceof Transaction2) {
1908
+ tx.transaction.sign(keypair);
1909
+ return { ...tx, transaction: tx.transaction.serialize() };
1910
+ }
1911
+ if (typeof tx.transaction === "object") {
1912
+ try {
1913
+ const transaction = Transaction2.from(tx.transaction);
1914
+ transaction.sign(keypair);
1915
+ return { ...tx, transaction: transaction.serialize(), signature: transaction.signature };
1916
+ } catch {
1917
+ throw new Error("Invalid transaction format");
1918
+ }
1919
+ }
1920
+ }
1921
+ throw new Error("Invalid transaction format");
1922
+ }
1923
+ async signMessage(message) {
1924
+ const keypair = this.getKeypair();
1925
+ const messageBytes = new TextEncoder().encode(message);
1926
+ const nacl = await import("tweetnacl");
1927
+ const secretKey = keypair.secretKey;
1928
+ if (secretKey.length !== 64) {
1929
+ throw new Error(`Invalid secret key length: expected 64, got ${secretKey.length}`);
1930
+ }
1931
+ const privateKeySlice = secretKey.slice(0, 32);
1932
+ const privateKeyBytes = new Uint8Array(privateKeySlice);
1933
+ if (privateKeyBytes.length !== 32) {
1934
+ throw new Error(`Invalid private key length: expected 32, got ${privateKeyBytes.length}`);
1935
+ }
1936
+ const signature = nacl.sign.detached(messageBytes, privateKeyBytes);
1937
+ return bs583.encode(signature);
1938
+ }
1939
+ getKeypairInstance() {
1940
+ return this.getKeypair();
1941
+ }
1942
+ async importFromMnemonic(mnemonic) {
1943
+ throw new Error("PrivateKeyWalletProvider does not support importing from mnemonics. Use MnemonicWalletProvider instead.");
1944
+ }
1945
+ async importFromPrivateKey(privateKey) {
1946
+ const keypair = Keypair2.fromSecretKey(bs583.decode(privateKey));
1947
+ const walletDetails = {
1948
+ provider: _PrivateKeyWalletProvider.PROVIDER_NAME,
1949
+ address: keypair.publicKey.toBase58(),
1950
+ privateKey: bs583.encode(keypair.secretKey),
1951
+ mnemonic: null
1952
+ };
1953
+ setWarpWalletInConfig2(this.config, this.chain.name, walletDetails);
1954
+ return walletDetails;
1955
+ }
1956
+ async export() {
1957
+ const keypair = this.getKeypair();
1958
+ const privateKey = getWarpWalletPrivateKeyFromConfig2(this.config, this.chain.name);
1959
+ const mnemonic = getWarpWalletMnemonicFromConfig2(this.config, this.chain.name);
1960
+ return {
1961
+ provider: _PrivateKeyWalletProvider.PROVIDER_NAME,
1962
+ address: keypair.publicKey.toBase58(),
1963
+ privateKey: privateKey || null,
1964
+ mnemonic: mnemonic || null
1965
+ };
1966
+ }
1967
+ async generate() {
1968
+ const keypair = Keypair2.generate();
1969
+ return {
1970
+ provider: _PrivateKeyWalletProvider.PROVIDER_NAME,
1971
+ address: keypair.publicKey.toBase58(),
1972
+ privateKey: bs583.encode(keypair.secretKey),
1973
+ mnemonic: null
1974
+ };
1975
+ }
1976
+ getKeypair() {
1977
+ if (this.keypair) return this.keypair;
1978
+ const privateKey = getWarpWalletPrivateKeyFromConfig2(this.config, this.chain.name);
1979
+ if (!privateKey) throw new Error("No private key provided");
1980
+ try {
1981
+ const secretKey = bs583.decode(privateKey);
1982
+ if (secretKey.length === 64) {
1983
+ this.keypair = Keypair2.fromSecretKey(secretKey);
1984
+ return this.keypair;
1985
+ } else if (secretKey.length === 32) {
1986
+ this.keypair = Keypair2.fromSeed(secretKey);
1987
+ return this.keypair;
1988
+ } else {
1989
+ throw new Error(`Invalid private key length: expected 32 or 64 bytes, got ${secretKey.length}`);
1990
+ }
1991
+ } catch (error) {
1992
+ if (error instanceof Error) {
1993
+ throw new Error(`Invalid private key format: ${error.message}`);
1994
+ }
1995
+ throw new Error("Invalid private key format");
1996
+ }
1997
+ }
1998
+ };
1999
+ _PrivateKeyWalletProvider.PROVIDER_NAME = "privateKey";
2000
+ var PrivateKeyWalletProvider = _PrivateKeyWalletProvider;
2001
+
2002
+ // src/providers/ReadOnlyWalletProvider.ts
2003
+ import { getWarpWalletAddressFromConfig as getWarpWalletAddressFromConfig5 } from "@joai/warps";
2004
+ var ReadOnlyWalletProvider = class {
2005
+ constructor(config, chain) {
2006
+ this.config = config;
2007
+ this.chain = chain;
2008
+ }
2009
+ async getAddress() {
2010
+ return getWarpWalletAddressFromConfig5(this.config, this.chain.name);
2011
+ }
2012
+ async getPublicKey() {
2013
+ return getWarpWalletAddressFromConfig5(this.config, this.chain.name);
2014
+ }
2015
+ async signTransaction(tx) {
2016
+ const address = await this.getAddress();
2017
+ throw new Error(`Wallet can not be used for signing: ${address}`);
2018
+ }
2019
+ async signMessage(message) {
2020
+ const address = await this.getAddress();
2021
+ throw new Error(`Wallet can not be used for signing: ${address}`);
2022
+ }
2023
+ async importFromMnemonic(mnemonic) {
2024
+ const address = getWarpWalletAddressFromConfig5(this.config, this.chain.name);
2025
+ throw new Error(`Wallet can not be used for signing: ${address}`);
2026
+ }
2027
+ async importFromPrivateKey(privateKey) {
2028
+ const address = getWarpWalletAddressFromConfig5(this.config, this.chain.name);
2029
+ throw new Error(`Wallet can not be used for signing: ${address}`);
2030
+ }
2031
+ async export() {
2032
+ const address = getWarpWalletAddressFromConfig5(this.config, this.chain.name);
2033
+ throw new Error(`Wallet can not be used for signing: ${address}`);
2034
+ }
2035
+ async generate() {
2036
+ const address = getWarpWalletAddressFromConfig5(this.config, this.chain.name);
2037
+ throw new Error(`Wallet can not be used for signing: ${address}`);
2038
+ }
2039
+ };
2040
+
2041
+ // src/WarpSolanaWallet.ts
2042
+ var WarpSolanaWallet = class {
2043
+ constructor(config, chain) {
2044
+ this.config = config;
2045
+ this.chain = chain;
2046
+ this.cachedAddress = null;
2047
+ this.cachedPublicKey = null;
2048
+ const providerConfig = getProviderConfig4(config, chain.name, config.env, chain.defaultApiUrl);
2049
+ this.connection = new Connection4(providerConfig.url, "confirmed");
2050
+ this.walletProvider = this.createProvider();
2051
+ this.initializeCache();
2052
+ }
2053
+ async signTransaction(tx) {
2054
+ if (!tx || typeof tx !== "object") throw new Error("Invalid transaction object");
2055
+ if (!this.walletProvider) throw new Error("No wallet provider available");
2056
+ if (this.walletProvider instanceof ReadOnlyWalletProvider) throw new Error(`Wallet (${this.chain.name}) is read-only`);
2057
+ return this.walletProvider.signTransaction(tx);
2058
+ }
2059
+ async signTransactions(txs) {
2060
+ return Promise.all(txs.map((tx) => this.signTransaction(tx)));
2061
+ }
2062
+ async signMessage(message) {
2063
+ if (!this.walletProvider) throw new Error("No wallet provider available");
2064
+ if (this.walletProvider instanceof ReadOnlyWalletProvider) throw new Error(`Wallet (${this.chain.name}) is read-only`);
2065
+ return this.walletProvider.signMessage(message);
2066
+ }
2067
+ async sendTransaction(tx) {
2068
+ if (!tx || typeof tx !== "object") throw new Error("Invalid transaction object");
2069
+ const transaction = this.resolveTransaction(tx);
2070
+ if (!transaction.signatures || transaction.signatures.length === 0 || !transaction.signatures.some((sig) => sig.some((b) => b !== 0))) {
2071
+ throw new Error("Transaction must be signed before sending");
2072
+ }
2073
+ try {
2074
+ const shouldSkipPreflight = await this.shouldSkipPreflight(transaction);
2075
+ return await this.sendWithRetry(transaction, shouldSkipPreflight);
2076
+ } catch (simError) {
2077
+ if (simError.message?.includes("MissingRequiredSignature")) {
2078
+ return await this.sendRawTransaction(transaction, { skipPreflight: true });
2079
+ }
2080
+ throw new Error(`Transaction send failed: ${simError?.message || String(simError)}`);
2081
+ }
2082
+ }
2083
+ async sendTransactions(txs) {
2084
+ return Promise.all(txs.map(async (tx) => this.sendTransaction(tx)));
2085
+ }
2086
+ async importFromMnemonic(mnemonic) {
2087
+ const walletProvider = this.createProviderForOperation("mnemonic");
2088
+ return await walletProvider.importFromMnemonic(mnemonic);
2089
+ }
2090
+ async importFromPrivateKey(privateKey) {
2091
+ const walletProvider = this.createProviderForOperation("privateKey");
2092
+ return await walletProvider.importFromPrivateKey(privateKey);
2093
+ }
2094
+ async export(provider) {
2095
+ const walletProvider = this.createProviderForOperation(provider);
2096
+ return await walletProvider.export();
2097
+ }
2098
+ async generate(provider) {
2099
+ const walletProvider = this.createProviderForOperation(provider);
2100
+ return await walletProvider.generate();
2101
+ }
2102
+ getAddress() {
2103
+ return this.cachedAddress;
2104
+ }
2105
+ getPublicKey() {
2106
+ return this.cachedPublicKey;
2107
+ }
2108
+ async registerX402Handlers(client) {
2109
+ if (!this.walletProvider) return {};
2110
+ const provider = this.walletProvider;
2111
+ const getKeypair = provider.getKeypairInstance;
2112
+ if (typeof getKeypair !== "function") return {};
2113
+ const keypair = getKeypair();
2114
+ if (!keypair || !keypair.secretKey) return {};
2115
+ const signer = await createKeyPairSignerFromBytes(keypair.secretKey);
2116
+ const handlers = {};
2117
+ for (const network of SupportedX402SolanaNetworks) {
2118
+ handlers[network] = () => {
2119
+ registerExactSvmScheme(client, { signer });
2120
+ };
2121
+ }
2122
+ return handlers;
2123
+ }
2124
+ createProvider() {
2125
+ const wallet = this.config.user?.wallets?.[this.chain.name];
2126
+ if (!wallet) return null;
2127
+ if (typeof wallet === "string") return new ReadOnlyWalletProvider(this.config, this.chain);
2128
+ return this.createProviderForOperation(wallet.provider);
2129
+ }
2130
+ initializeCache() {
2131
+ initializeWalletCache(this.walletProvider).then((cache) => {
2132
+ this.cachedAddress = cache.address;
2133
+ this.cachedPublicKey = cache.publicKey;
2134
+ });
2135
+ }
2136
+ createProviderForOperation(provider) {
2137
+ const customWalletProviders = this.config.walletProviders?.[this.chain.name];
2138
+ const providerFactory = customWalletProviders?.[provider];
2139
+ if (providerFactory) {
2140
+ const walletProvider = providerFactory(this.config, this.chain);
2141
+ if (!walletProvider) throw new Error(`Custom wallet provider factory returned null for ${provider}`);
2142
+ return walletProvider;
2143
+ }
2144
+ if (provider === "privateKey") return new PrivateKeyWalletProvider(this.config, this.chain);
2145
+ if (provider === "mnemonic") return new MnemonicWalletProvider(this.config, this.chain);
2146
+ throw new Error(`Unsupported wallet provider for ${this.chain.name}: ${provider}`);
2147
+ }
2148
+ resolveTransaction(tx) {
2149
+ if (tx instanceof VersionedTransaction4) {
2150
+ if (tx.version === void 0 || tx.version === "legacy") {
2151
+ throw new Error("Transaction must be a VersionedTransaction (v0), not legacy");
2152
+ }
2153
+ return tx;
2154
+ }
2155
+ if (tx instanceof Transaction3) {
2156
+ throw new Error("Legacy Transaction format is not supported. All transactions must use VersionedTransaction (v0).");
2157
+ }
2158
+ if (tx.transaction instanceof VersionedTransaction4) {
2159
+ if (tx.transaction.version === void 0 || tx.transaction.version === "legacy") {
2160
+ throw new Error("Transaction must be a VersionedTransaction (v0), not legacy");
2161
+ }
2162
+ return tx.transaction;
2163
+ }
2164
+ if (tx.transaction instanceof Transaction3) {
2165
+ throw new Error("Legacy Transaction format is not supported. All transactions must use VersionedTransaction (v0).");
2166
+ }
2167
+ if (!tx.transaction) {
2168
+ throw new Error("Transaction must be signed before sending");
2169
+ }
2170
+ throw new Error("Invalid transaction format - only VersionedTransaction is supported");
2171
+ }
2172
+ async shouldSkipPreflight(transaction) {
2173
+ if (!transaction.signatures || transaction.signatures.length === 0 || !transaction.signatures.some((sig) => sig.some((b) => b !== 0))) {
2174
+ return false;
2175
+ }
2176
+ try {
2177
+ const simulation = await this.connection.simulateTransaction(transaction, {
2178
+ replaceRecentBlockhash: true,
2179
+ sigVerify: false
2180
+ });
2181
+ if (simulation.value.err) {
2182
+ const errMsg = JSON.stringify(simulation.value.err);
2183
+ if (errMsg.includes('"Custom": 17') || errMsg.includes('"Custom":17') || errMsg.includes("0x11")) {
2184
+ return true;
2185
+ }
2186
+ throw new Error(`Transaction simulation failed: ${errMsg}`);
2187
+ }
2188
+ } catch (error) {
2189
+ if (error.message?.includes("Transaction simulation failed")) throw error;
2190
+ }
2191
+ return false;
2192
+ }
2193
+ async sendWithRetry(transaction, skipPreflight) {
2194
+ if (skipPreflight) {
2195
+ return this.sendRawTransaction(transaction, { skipPreflight: true });
2196
+ }
2197
+ try {
2198
+ return await this.sendRawTransaction(transaction, { skipPreflight: false, preflightCommitment: "confirmed" });
2199
+ } catch (error) {
2200
+ if (this.isSimulationError(error)) {
2201
+ return this.sendRawTransaction(transaction, { skipPreflight: true });
2202
+ }
2203
+ throw error;
2204
+ }
2205
+ }
2206
+ async sendRawTransaction(transaction, options) {
2207
+ const signature = await this.connection.sendRawTransaction(transaction.serialize(), {
2208
+ skipPreflight: options.skipPreflight,
2209
+ maxRetries: options.maxRetries || 3,
2210
+ preflightCommitment: options.preflightCommitment
2211
+ });
2212
+ if (!signature || typeof signature !== "string" || signature.length < 32) {
2213
+ throw new Error("Invalid transaction signature received");
2214
+ }
2215
+ return signature;
2216
+ }
2217
+ isSimulationError(error) {
2218
+ const msg = error?.message?.toLowerCase() || "";
2219
+ return msg.includes("simulation") || msg.includes("preflight") || msg.includes("0x1") || msg.includes("custom program error");
2220
+ }
2221
+ };
2222
+
2223
+ // src/chains/common.ts
2224
+ var createSolanaAdapter = (chainName, chainInfos) => {
2225
+ return (config, fallback) => {
2226
+ if (!fallback) throw new Error(`${chainName} adapter requires a fallback adapter`);
2227
+ return {
2228
+ chainInfo: chainInfos[config.env],
2229
+ builder: () => fallback.builder(),
2230
+ executor: new WarpSolanaExecutor(config, chainInfos[config.env]),
2231
+ output: new WarpSolanaOutput(config, chainInfos[config.env]),
2232
+ serializer: new WarpSolanaSerializer(),
2233
+ registry: fallback.registry,
2234
+ explorer: new WarpSolanaExplorer(chainInfos[config.env], config),
2235
+ abiBuilder: () => fallback.abiBuilder(),
2236
+ brandBuilder: () => fallback.brandBuilder(),
2237
+ dataLoader: new WarpSolanaDataLoader(config, chainInfos[config.env]),
2238
+ wallet: new WarpSolanaWallet(config, chainInfos[config.env])
2239
+ };
2240
+ };
2241
+ };
2242
+
2243
+ // src/chains/solana.ts
2244
+ var NativeTokenSol = {
2245
+ chain: WarpChainName5.Solana,
2246
+ identifier: "SOL",
2247
+ symbol: "SOL",
2248
+ name: "SOL",
2249
+ decimals: 9,
2250
+ logoUrl: "https://raw.githubusercontent.com/JoAiHQ/assets/refs/heads/main/tokens/logos/sol.svg"
2251
+ };
2252
+ var SolanaAdapter = createSolanaAdapter(WarpChainName5.Solana, {
2253
+ mainnet: {
2254
+ name: WarpChainName5.Solana,
2255
+ displayName: "Solana Mainnet",
2256
+ chainId: "101",
2257
+ blockTime: 400,
2258
+ addressHrp: "",
2259
+ defaultApiUrl: "https://api.mainnet-beta.solana.com",
2260
+ logoUrl: "https://raw.githubusercontent.com/JoAiHQ/assets/refs/heads/main/chains/logos/solana.svg",
2261
+ nativeToken: NativeTokenSol
2262
+ },
2263
+ testnet: {
2264
+ name: WarpChainName5.Solana,
2265
+ displayName: "Solana Testnet",
2266
+ chainId: "103",
2267
+ blockTime: 400,
2268
+ addressHrp: "",
2269
+ defaultApiUrl: "https://api.testnet.solana.com",
2270
+ logoUrl: "https://raw.githubusercontent.com/JoAiHQ/assets/refs/heads/main/chains/logos/solana.svg",
2271
+ nativeToken: NativeTokenSol
2272
+ },
2273
+ devnet: {
2274
+ name: WarpChainName5.Solana,
2275
+ displayName: "Solana Devnet",
2276
+ chainId: "103",
2277
+ blockTime: 400,
2278
+ addressHrp: "",
2279
+ defaultApiUrl: "https://api.devnet.solana.com",
2280
+ logoUrl: "https://raw.githubusercontent.com/JoAiHQ/assets/refs/heads/main/chains/logos/solana.svg",
2281
+ nativeToken: NativeTokenSol
2282
+ }
2283
+ });
2284
+ export {
2285
+ ExplorerUrls,
2286
+ KnownTokens,
2287
+ NativeTokenSol,
2288
+ SolanaAdapter,
2289
+ SolanaExplorerMap,
2290
+ SolanaExplorerNames,
2291
+ SolanaExplorerUrls,
2292
+ SolanaExplorers,
2293
+ SupportedX402SolanaNetworks,
2294
+ WarpSolanaConstants,
2295
+ WarpSolanaDataLoader,
2296
+ WarpSolanaExecutor,
2297
+ WarpSolanaExplorer,
2298
+ WarpSolanaOutput,
2299
+ WarpSolanaSerializer,
2300
+ WarpSolanaWallet,
2301
+ X402SolanaNetworkIdentifiers,
2302
+ findKnownTokenById,
2303
+ getKnownTokensForChain
2304
+ };
2305
+ //# sourceMappingURL=index.mjs.map