@joai/warps-adapter-solana 1.0.0 → 1.0.2

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 CHANGED
@@ -9,8 +9,7 @@ import {
9
9
  WarpCache,
10
10
  WarpCacheKey
11
11
  } from "@joai/warps";
12
- import { Connection, PublicKey } from "@solana/web3.js";
13
- import { getMint } from "@solana/spl-token";
12
+ import { Connection as Connection2, PublicKey as PublicKey2 } from "@solana/web3.js";
14
13
 
15
14
  // src/constants.ts
16
15
  var WarpSolanaConstants = {
@@ -72,6 +71,58 @@ var X402SolanaNetworkIdentifiers = {
72
71
  };
73
72
  var SupportedX402SolanaNetworks = [X402SolanaNetworkIdentifiers.Mainnet, X402SolanaNetworkIdentifiers.Devnet];
74
73
 
74
+ // src/tokenProgram.ts
75
+ import { PublicKey, SystemProgram, TransactionInstruction } from "@solana/web3.js";
76
+ var MINT_SIZE = 82;
77
+ var TOKEN_TRANSFER_INSTRUCTION = 3;
78
+ var TOKEN_PROGRAM_ID = new PublicKey(WarpSolanaConstants.Programs.TokenProgram);
79
+ var ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
80
+ var getAssociatedTokenAddress = async (mint, owner, allowOwnerOffCurve = false, programId = TOKEN_PROGRAM_ID, associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID) => getAssociatedTokenAddressSync(mint, owner, allowOwnerOffCurve, programId, associatedTokenProgramId);
81
+ var getAssociatedTokenAddressSync = (mint, owner, allowOwnerOffCurve = false, programId = TOKEN_PROGRAM_ID, associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID) => {
82
+ if (!allowOwnerOffCurve && !PublicKey.isOnCurve(owner.toBuffer())) {
83
+ throw new Error("Owner cannot be a PDA");
84
+ }
85
+ const [address] = PublicKey.findProgramAddressSync([owner.toBuffer(), programId.toBuffer(), mint.toBuffer()], associatedTokenProgramId);
86
+ return address;
87
+ };
88
+ var createAssociatedTokenAccountInstruction = (payer, associatedToken, owner, mint, programId = TOKEN_PROGRAM_ID, associatedTokenProgramId = ASSOCIATED_TOKEN_PROGRAM_ID) => new TransactionInstruction({
89
+ keys: [
90
+ { pubkey: payer, isSigner: true, isWritable: true },
91
+ { pubkey: associatedToken, isSigner: false, isWritable: true },
92
+ { pubkey: owner, isSigner: false, isWritable: false },
93
+ { pubkey: mint, isSigner: false, isWritable: false },
94
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
95
+ { pubkey: programId, isSigner: false, isWritable: false }
96
+ ],
97
+ programId: associatedTokenProgramId,
98
+ data: Buffer.alloc(0)
99
+ });
100
+ var createTransferInstruction = (source, destination, owner, amount, programId = TOKEN_PROGRAM_ID) => {
101
+ const data = Buffer.alloc(9);
102
+ data.writeUInt8(TOKEN_TRANSFER_INSTRUCTION, 0);
103
+ data.writeBigUInt64LE(BigInt(amount), 1);
104
+ return new TransactionInstruction({
105
+ keys: [
106
+ { pubkey: source, isSigner: false, isWritable: true },
107
+ { pubkey: destination, isSigner: false, isWritable: true },
108
+ { pubkey: owner, isSigner: true, isWritable: false }
109
+ ],
110
+ programId,
111
+ data
112
+ });
113
+ };
114
+ var getMint = async (connection, address, commitment, programId = TOKEN_PROGRAM_ID) => {
115
+ const info = await connection.getAccountInfo(address, commitment);
116
+ if (!info) throw new Error("Token mint account not found");
117
+ if (!info.owner.equals(programId)) throw new Error("Token mint account owner mismatch");
118
+ if (info.data.length < MINT_SIZE) throw new Error("Token mint account has invalid size");
119
+ return {
120
+ address,
121
+ decimals: info.data.readUInt8(44),
122
+ isInitialized: info.data.readUInt8(45) !== 0
123
+ };
124
+ };
125
+
75
126
  // src/tokens.ts
76
127
  import { WarpChainName as WarpChainName4 } from "@joai/warps";
77
128
 
@@ -275,12 +326,12 @@ var WarpSolanaDataLoader = class {
275
326
  this.config = config;
276
327
  this.chain = chain;
277
328
  const providerConfig = getProviderConfig(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
278
- this.connection = new Connection(providerConfig.url, "confirmed");
329
+ this.connection = new Connection2(providerConfig.url, "confirmed");
279
330
  this.cache = new WarpCache(config.env, config.cache);
280
331
  }
281
332
  async getAccount(address) {
282
333
  try {
283
- const publicKey = new PublicKey(address);
334
+ const publicKey = new PublicKey2(address);
284
335
  const balance = await this.connection.getBalance(publicKey);
285
336
  return {
286
337
  chain: this.chain.name,
@@ -378,9 +429,9 @@ var WarpSolanaDataLoader = class {
378
429
  }
379
430
  async getTokenBalances(address) {
380
431
  try {
381
- const publicKey = new PublicKey(address);
432
+ const publicKey = new PublicKey2(address);
382
433
  const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(publicKey, {
383
- programId: new PublicKey(WarpSolanaConstants.Programs.TokenProgram)
434
+ programId: new PublicKey2(WarpSolanaConstants.Programs.TokenProgram)
384
435
  });
385
436
  const env = this.config.env === "mainnet" ? "mainnet" : this.config.env === "devnet" ? "devnet" : "testnet";
386
437
  const knownTokens = getKnownTokensForChain(this.chain.name, env);
@@ -422,7 +473,7 @@ var WarpSolanaDataLoader = class {
422
473
  }
423
474
  async getTokenMetadata(tokenAddress) {
424
475
  try {
425
- const mintPublicKey = new PublicKey(tokenAddress);
476
+ const mintPublicKey = new PublicKey2(tokenAddress);
426
477
  const mintInfo = await getMint(this.connection, mintPublicKey);
427
478
  return {
428
479
  name: "Unknown Token",
@@ -572,8 +623,7 @@ var WarpSolanaDataLoader = class {
572
623
  };
573
624
 
574
625
  // 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";
626
+ import { ComputeBudgetProgram, Connection as Connection4, MessageV0, PublicKey as PublicKey4, SystemProgram as SystemProgram2, TransactionInstruction as TransactionInstruction2, VersionedTransaction } from "@solana/web3.js";
577
627
  import {
578
628
  applyOutputToMessages,
579
629
  extractResolvedInputValues as extractResolvedInputValues2,
@@ -594,14 +644,14 @@ import {
594
644
  WarpCache as WarpCache2,
595
645
  WarpCacheKey as WarpCacheKey2
596
646
  } from "@joai/warps";
597
- import { Connection as Connection2 } from "@solana/web3.js";
647
+ import { Connection as Connection3 } from "@solana/web3.js";
598
648
 
599
649
  // src/WarpSolanaSerializer.ts
600
650
  import {
601
651
  WarpConstants,
602
652
  WarpSerializer
603
653
  } from "@joai/warps";
604
- import { PublicKey as PublicKey2 } from "@solana/web3.js";
654
+ import { PublicKey as PublicKey3 } from "@solana/web3.js";
605
655
  import bs58 from "bs58";
606
656
  var WarpSolanaSerializer = class {
607
657
  constructor() {
@@ -614,7 +664,7 @@ var WarpSolanaSerializer = class {
614
664
  if (typeof value === "string") {
615
665
  if (value.length >= 32 && value.length <= 44) {
616
666
  try {
617
- const pubkey = new PublicKey2(value);
667
+ const pubkey = new PublicKey3(value);
618
668
  if (pubkey.toBase58() === value && /^[1-9A-HJ-NP-Za-km-z]+$/.test(value)) {
619
669
  return `address:${value}`;
620
670
  }
@@ -641,7 +691,7 @@ var WarpSolanaSerializer = class {
641
691
  if (typeof value === "boolean") {
642
692
  return `boolean:${value}`;
643
693
  }
644
- if (value instanceof PublicKey2) {
694
+ if (value instanceof PublicKey3) {
645
695
  return `address:${value.toBase58()}`;
646
696
  }
647
697
  if (value instanceof Uint8Array) {
@@ -791,7 +841,7 @@ var WarpSolanaOutput = class {
791
841
  this.chain = chain;
792
842
  this.serializer = new WarpSolanaSerializer();
793
843
  const providerConfig = getProviderConfig2(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
794
- this.connection = new Connection2(providerConfig.url, "confirmed");
844
+ this.connection = new Connection3(providerConfig.url, "confirmed");
795
845
  this.cache = new WarpCache2(config.env, config.cache);
796
846
  }
797
847
  async getActionExecution(warp, actionIndex, tx) {
@@ -918,7 +968,7 @@ var WarpSolanaOutput = class {
918
968
  output[key] = path;
919
969
  }
920
970
  }
921
- return { values, output: await evaluateOutputCommon(warp, output, actionIndex, inputs, this.serializer.coreSerializer, this.config) };
971
+ return { values, output: await evaluateOutputCommon(warp, output, nativeValues, actionIndex, inputs, this.serializer.coreSerializer, this.config) };
922
972
  }
923
973
  async getTransactionStatus(txHash) {
924
974
  try {
@@ -967,7 +1017,7 @@ var WarpSolanaExecutor = class {
967
1017
  this.chain = chain;
968
1018
  this.serializer = new WarpSolanaSerializer();
969
1019
  const providerConfig = getProviderConfig3(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
970
- this.connection = new Connection3(providerConfig.url, "confirmed");
1020
+ this.connection = new Connection4(providerConfig.url, "confirmed");
971
1021
  this.output = new WarpSolanaOutput(config, this.chain);
972
1022
  }
973
1023
  async createTransaction(executable) {
@@ -996,14 +1046,14 @@ var WarpSolanaExecutor = class {
996
1046
  }
997
1047
  const instructions = [];
998
1048
  if (executable.value > 0n) {
999
- instructions.push(SystemProgram.transfer({ fromPubkey, toPubkey: destinationPubkey, lamports: Number(executable.value) }));
1049
+ instructions.push(SystemProgram2.transfer({ fromPubkey, toPubkey: destinationPubkey, lamports: Number(executable.value) }));
1000
1050
  }
1001
1051
  if (executable.data) {
1002
1052
  const data = this.serializer.stringToTyped(executable.data);
1003
1053
  if (data && typeof data === "string") {
1004
1054
  const dataBuffer = Buffer.from(data, "base64");
1005
1055
  instructions.push(
1006
- new TransactionInstruction({
1056
+ new TransactionInstruction2({
1007
1057
  keys: [
1008
1058
  { pubkey: fromPubkey, isSigner: true, isWritable: true },
1009
1059
  { pubkey: destinationPubkey, isSigner: false, isWritable: true }
@@ -1028,26 +1078,36 @@ var WarpSolanaExecutor = class {
1028
1078
  const argsToUse = this.extractContractArgs(executable);
1029
1079
  const nativeArgs = argsToUse.map((arg) => this.serializer.coreSerializer.stringToNative(arg)[1]);
1030
1080
  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 }));
1081
+ const parsedAbi = this.parseAbi(action);
1082
+ const abiAccounts = parsedAbi?.instructions?.[action.func]?.accounts ?? null;
1083
+ const accounts = await this.buildInstructionAccounts(action, executable, fromPubkey, programId, abiAccounts);
1084
+ await this.ensureATAs(abiAccounts, accounts, fromPubkey, instructions);
1085
+ instructions.push(new TransactionInstruction2({ keys: accounts, programId, data: instructionData }));
1034
1086
  if (executable.value > 0n) {
1035
- instructions.push(SystemProgram.transfer({ fromPubkey, toPubkey: programId, lamports: Number(executable.value) }));
1087
+ instructions.push(SystemProgram2.transfer({ fromPubkey, toPubkey: programId, lamports: Number(executable.value) }));
1036
1088
  }
1037
1089
  return this.setTransactionDefaults(instructions, fromPubkey);
1038
1090
  }
1039
- async ensureATAs(action, accounts, fromPubkey, instructions) {
1040
- if (!action.accounts || !Array.isArray(action.accounts)) return;
1091
+ parseAbi(action) {
1092
+ if (!action.abi || typeof action.abi !== "string") return null;
1093
+ try {
1094
+ return JSON.parse(action.abi);
1095
+ } catch {
1096
+ return null;
1097
+ }
1098
+ }
1099
+ async ensureATAs(abiAccounts, accounts, fromPubkey, instructions) {
1100
+ if (!abiAccounts || !Array.isArray(abiAccounts)) return;
1041
1101
  const createdATAs = /* @__PURE__ */ new Set();
1042
- for (let idx = 0; idx < action.accounts.length; idx++) {
1043
- const accountDef = action.accounts[idx];
1102
+ for (let idx = 0; idx < abiAccounts.length; idx++) {
1103
+ const accountDef = abiAccounts[idx];
1044
1104
  const accountStr = typeof accountDef === "string" ? accountDef : JSON.stringify(accountDef);
1045
1105
  if (accountStr.includes("{{USER_ATA:")) {
1046
1106
  const match = accountStr.match(/USER_ATA[:\s]*([^"}\s]+)/);
1047
1107
  if (match) {
1048
1108
  const mintAddress = match[1];
1049
1109
  try {
1050
- const mintPubkey = new PublicKey3(mintAddress);
1110
+ const mintPubkey = new PublicKey4(mintAddress);
1051
1111
  const expectedAta = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
1052
1112
  const ataKey = expectedAta.toBase58();
1053
1113
  if (!createdATAs.has(ataKey)) {
@@ -1068,8 +1128,8 @@ var WarpSolanaExecutor = class {
1068
1128
  const mintAddress = match[1];
1069
1129
  const receiverAddress = match[2];
1070
1130
  try {
1071
- const mintPubkey = new PublicKey3(mintAddress);
1072
- const receiverPubkey = new PublicKey3(receiverAddress);
1131
+ const mintPubkey = new PublicKey4(mintAddress);
1132
+ const receiverPubkey = new PublicKey4(receiverAddress);
1073
1133
  const expectedAta = await getAssociatedTokenAddress(mintPubkey, receiverPubkey);
1074
1134
  const ataKey = expectedAta.toBase58();
1075
1135
  if (!createdATAs.has(ataKey)) {
@@ -1153,7 +1213,7 @@ var WarpSolanaExecutor = class {
1153
1213
  buffers.push(Buffer.from(String(arg), "utf8"));
1154
1214
  } else if (def.type === "publicKey" || def.type === "pubkey") {
1155
1215
  try {
1156
- const pubkey = new PublicKey3(arg);
1216
+ const pubkey = new PublicKey4(arg);
1157
1217
  buffers.push(Buffer.from(pubkey.toBuffer()));
1158
1218
  } catch {
1159
1219
  buffers.push(Buffer.from(String(arg), "utf8"));
@@ -1164,7 +1224,7 @@ var WarpSolanaExecutor = class {
1164
1224
  }
1165
1225
  return Buffer.concat(buffers);
1166
1226
  }
1167
- async buildInstructionAccounts(action, executable, fromPubkey, programId) {
1227
+ async buildInstructionAccounts(action, executable, fromPubkey, programId, abiAccounts) {
1168
1228
  const accounts = [];
1169
1229
  const accountInputs = this.extractAccountInputs(action, executable);
1170
1230
  if (accountInputs.length > 0) {
@@ -1178,13 +1238,11 @@ var WarpSolanaExecutor = class {
1178
1238
  }
1179
1239
  return accounts;
1180
1240
  }
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];
1241
+ if (!abiAccounts || !Array.isArray(abiAccounts)) return accounts;
1242
+ for (let idx = 0; idx < abiAccounts.length; idx++) {
1243
+ const accountDef = abiAccounts[idx];
1184
1244
  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) {
1245
+ if (!address || address.length === 0) {
1188
1246
  throw new Error(`Invalid account definition at index ${idx}: ${JSON.stringify(accountDef)}`);
1189
1247
  }
1190
1248
  if (address === "{{USER_WALLET}}" || typeof address === "string" && address.includes("{{USER_WALLET}}")) {
@@ -1236,7 +1294,7 @@ var WarpSolanaExecutor = class {
1236
1294
  if (accountInput.input.as?.startsWith("USER_ATA:") || accountInput.input.as?.startsWith("RECEIVER_ATA:")) {
1237
1295
  return await this.resolveAccountPubkey(`{{${accountInput.input.as}}}`, fromPubkey);
1238
1296
  }
1239
- return new PublicKey3(address);
1297
+ return new PublicKey4(address);
1240
1298
  }
1241
1299
  interpolateAccountAddress(address, resolvedInputs) {
1242
1300
  if (!address.includes("{{")) return address;
@@ -1266,6 +1324,22 @@ var WarpSolanaExecutor = class {
1266
1324
  }
1267
1325
  }
1268
1326
  }
1327
+ if (address.includes("{{USER_ATA:") || address.includes("{{RECEIVER_ATA:")) {
1328
+ for (const resolved of resolvedInputs) {
1329
+ if (!resolved.input?.as) continue;
1330
+ const key = resolved.input.as.toUpperCase();
1331
+ if (address.includes(key)) {
1332
+ let value = resolved.value;
1333
+ if (typeof value === "string" && value.includes(":")) {
1334
+ value = value.split(":")[1];
1335
+ }
1336
+ if (value) {
1337
+ address = address.replace(new RegExp(key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), String(value));
1338
+ }
1339
+ }
1340
+ }
1341
+ return address;
1342
+ }
1269
1343
  return address;
1270
1344
  }
1271
1345
  async createTokenTransferTransaction(executable, userWallet, destinationPubkey) {
@@ -1277,8 +1351,8 @@ var WarpSolanaExecutor = class {
1277
1351
  if (nativeTokenTransfers.length === 1 && splTokenTransfers.length === 0) {
1278
1352
  const transfer = nativeTokenTransfers[0];
1279
1353
  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);
1354
+ const fromPubkey = new PublicKey4(userWallet);
1355
+ return this.setTransactionDefaults([SystemProgram2.transfer({ fromPubkey, toPubkey: destinationPubkey, lamports: Number(transfer.amount) })], fromPubkey);
1282
1356
  }
1283
1357
  if (nativeTokenTransfers.length === 0 && splTokenTransfers.length === 1) {
1284
1358
  return this.createSingleTokenTransfer(executable, splTokenTransfers[0], userWallet, destinationPubkey);
@@ -1287,8 +1361,8 @@ var WarpSolanaExecutor = class {
1287
1361
  throw new Error("WarpSolanaExecutor: Invalid transfer configuration");
1288
1362
  }
1289
1363
  async createSingleTokenTransfer(executable, transfer, userWallet, destinationPubkey) {
1290
- const mintAddress = new PublicKey3(transfer.identifier);
1291
- const fromPubkey = new PublicKey3(userWallet);
1364
+ const mintAddress = new PublicKey4(transfer.identifier);
1365
+ const fromPubkey = new PublicKey4(userWallet);
1292
1366
  const sourceTokenAccount = await getAssociatedTokenAddress(mintAddress, fromPubkey);
1293
1367
  const destinationTokenAccount = await getAssociatedTokenAddress(mintAddress, destinationPubkey);
1294
1368
  if (!await this.connection.getAccountInfo(sourceTokenAccount)) {
@@ -1306,7 +1380,7 @@ var WarpSolanaExecutor = class {
1306
1380
  if (action.type !== "query") throw new Error(`WarpSolanaExecutor: Invalid action type for executeQuery: ${action.type}`);
1307
1381
  if (!action.func) throw new Error("WarpSolanaExecutor: Query action must have a function name");
1308
1382
  if (!executable.destination) throw new Error("WarpSolanaExecutor: Query address is required");
1309
- const queryAddress = new PublicKey3(executable.destination);
1383
+ const queryAddress = new PublicKey4(executable.destination);
1310
1384
  const nativeArgs = executable.args.map((arg) => this.serializer.coreSerializer.stringToNative(arg)[1]);
1311
1385
  let decodedResult = [];
1312
1386
  let isSuccess = true;
@@ -1362,32 +1436,19 @@ var WarpSolanaExecutor = class {
1362
1436
  resolvedInputs
1363
1437
  };
1364
1438
  }
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
1439
  async setTransactionDefaults(instructions, fromPubkey) {
1375
1440
  const { blockhash } = await this.connection.getLatestBlockhash("confirmed");
1376
1441
  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;
1442
+ const messageV0 = MessageV0.compile({
1443
+ payerKey: fromPubkey,
1444
+ instructions: allInstructions,
1445
+ recentBlockhash: blockhash
1446
+ });
1447
+ return new VersionedTransaction(messageV0);
1387
1448
  }
1388
1449
  toPublicKey(address, errorMsg) {
1389
1450
  try {
1390
- return new PublicKey3(address);
1451
+ return new PublicKey4(address);
1391
1452
  } catch {
1392
1453
  throw new Error(`WarpSolanaExecutor: ${errorMsg}`);
1393
1454
  }
@@ -1423,20 +1484,8 @@ var WarpSolanaExecutor = class {
1423
1484
  extractAccountAddress(accountDef) {
1424
1485
  if (typeof accountDef === "string") return accountDef;
1425
1486
  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]];
1487
+ const address = accountDef.address || accountDef.pubkey;
1488
+ if (typeof address === "string") return address;
1440
1489
  return void 0;
1441
1490
  }
1442
1491
  async resolveAccountPubkey(address, fromPubkey) {
@@ -1448,7 +1497,7 @@ var WarpSolanaExecutor = class {
1448
1497
  if (!mintAddress || mintAddress.includes("{{")) {
1449
1498
  throw new Error(`Invalid USER_ATA placeholder: ${address}. Mint address must be resolved first.`);
1450
1499
  }
1451
- const mintPubkey = new PublicKey3(mintAddress);
1500
+ const mintPubkey = new PublicKey4(mintAddress);
1452
1501
  return await getAssociatedTokenAddress(mintPubkey, fromPubkey);
1453
1502
  }
1454
1503
  if (address.startsWith("{{RECEIVER_ATA:") && address.endsWith("}}")) {
@@ -1462,12 +1511,12 @@ var WarpSolanaExecutor = class {
1462
1511
  }
1463
1512
  if (mintAddress.includes(":")) mintAddress = mintAddress.split(":")[1];
1464
1513
  if (receiverAddress.includes(":")) receiverAddress = receiverAddress.split(":")[1];
1465
- const mintPubkey = new PublicKey3(mintAddress);
1466
- const receiverPubkey = new PublicKey3(receiverAddress);
1514
+ const mintPubkey = new PublicKey4(mintAddress);
1515
+ const receiverPubkey = new PublicKey4(receiverAddress);
1467
1516
  return await getAssociatedTokenAddress(mintPubkey, receiverPubkey);
1468
1517
  }
1469
1518
  }
1470
- return new PublicKey3(address);
1519
+ return new PublicKey4(address);
1471
1520
  }
1472
1521
  determineAccountFlags(accountDef, pubkey, fromPubkey) {
1473
1522
  const accountMeta = typeof accountDef === "object" ? accountDef : {};
@@ -1485,81 +1534,6 @@ var WarpSolanaExecutor = class {
1485
1534
  const computeUnitPriceIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: WarpSolanaConstants.PriorityFee.Default });
1486
1535
  return [computeUnitLimitIx, computeUnitPriceIx, ...instructions];
1487
1536
  }
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
1537
  };
1564
1538
 
1565
1539
  // src/WarpSolanaExplorer.ts
@@ -1713,7 +1687,7 @@ import {
1713
1687
  initializeWalletCache
1714
1688
  } from "@joai/warps";
1715
1689
  import { createKeyPairSignerFromBytes } from "@solana/kit";
1716
- import { Connection as Connection4, Transaction as Transaction3, VersionedTransaction as VersionedTransaction4 } from "@solana/web3.js";
1690
+ import { Connection as Connection5, Transaction as Transaction3, VersionedTransaction as VersionedTransaction4 } from "@solana/web3.js";
1717
1691
  import { registerExactSvmScheme } from "@x402/svm/exact/client";
1718
1692
 
1719
1693
  // src/providers/MnemonicWalletProvider.ts
@@ -2046,7 +2020,7 @@ var WarpSolanaWallet = class {
2046
2020
  this.cachedAddress = null;
2047
2021
  this.cachedPublicKey = null;
2048
2022
  const providerConfig = getProviderConfig4(config, chain.name, config.env, chain.defaultApiUrl);
2049
- this.connection = new Connection4(providerConfig.url, "confirmed");
2023
+ this.connection = new Connection5(providerConfig.url, "confirmed");
2050
2024
  this.walletProvider = this.createProvider();
2051
2025
  this.initializeCache();
2052
2026
  }
@@ -2147,29 +2121,51 @@ var WarpSolanaWallet = class {
2147
2121
  throw new Error(`Unsupported wallet provider for ${this.chain.name}: ${provider}`);
2148
2122
  }
2149
2123
  resolveTransaction(tx) {
2150
- if (tx instanceof VersionedTransaction4) {
2151
- if (tx.version === void 0 || tx.version === "legacy") {
2152
- throw new Error("Transaction must be a VersionedTransaction (v0), not legacy");
2153
- }
2154
- return tx;
2155
- }
2124
+ const directVersionedTransaction = this.asVersionedTransaction(tx);
2125
+ if (directVersionedTransaction) return directVersionedTransaction;
2156
2126
  if (tx instanceof Transaction3) {
2157
2127
  throw new Error("Legacy Transaction format is not supported. All transactions must use VersionedTransaction (v0).");
2158
2128
  }
2159
- if (tx.transaction instanceof VersionedTransaction4) {
2160
- if (tx.transaction.version === void 0 || tx.transaction.version === "legacy") {
2161
- throw new Error("Transaction must be a VersionedTransaction (v0), not legacy");
2162
- }
2163
- return tx.transaction;
2164
- }
2165
- if (tx.transaction instanceof Transaction3) {
2129
+ const nestedTransaction = tx.transaction;
2130
+ const nestedVersionedTransaction = this.asVersionedTransaction(nestedTransaction);
2131
+ if (nestedVersionedTransaction) return nestedVersionedTransaction;
2132
+ if (nestedTransaction instanceof Transaction3) {
2166
2133
  throw new Error("Legacy Transaction format is not supported. All transactions must use VersionedTransaction (v0).");
2167
2134
  }
2168
- if (!tx.transaction) {
2135
+ const serializedTransaction = this.toSerializedTransactionBytes(nestedTransaction);
2136
+ if (serializedTransaction) {
2137
+ try {
2138
+ return this.asVersionedTransactionOrThrow(VersionedTransaction4.deserialize(serializedTransaction));
2139
+ } catch {
2140
+ throw new Error("Invalid serialized transaction format. Expected a VersionedTransaction payload.");
2141
+ }
2142
+ }
2143
+ if (!nestedTransaction) {
2169
2144
  throw new Error("Transaction must be signed before sending");
2170
2145
  }
2171
2146
  throw new Error("Invalid transaction format - only VersionedTransaction is supported");
2172
2147
  }
2148
+ asVersionedTransaction(tx) {
2149
+ if (!(tx instanceof VersionedTransaction4)) return null;
2150
+ return this.asVersionedTransactionOrThrow(tx);
2151
+ }
2152
+ asVersionedTransactionOrThrow(tx) {
2153
+ if (tx.version === void 0 || tx.version === "legacy") {
2154
+ throw new Error("Transaction must be a VersionedTransaction (v0), not legacy");
2155
+ }
2156
+ return tx;
2157
+ }
2158
+ toSerializedTransactionBytes(value) {
2159
+ if (value instanceof Uint8Array) return value;
2160
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) return new Uint8Array(value);
2161
+ if (Array.isArray(value) && value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)) {
2162
+ return Uint8Array.from(value);
2163
+ }
2164
+ if (typeof value === "string" && value.trim() !== "") {
2165
+ return Uint8Array.from(Buffer.from(value.trim(), "base64"));
2166
+ }
2167
+ return null;
2168
+ }
2173
2169
  async shouldSkipPreflight(transaction) {
2174
2170
  if (!transaction.signatures || transaction.signatures.length === 0 || !transaction.signatures.some((sig) => sig.some((b) => b !== 0))) {
2175
2171
  return false;