@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.d.cts +4 -6
- package/dist/index.d.ts +4 -6
- package/dist/index.js +199 -203
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +168 -172
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -8
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
|
|
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
|
|
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
|
|
432
|
+
const publicKey = new PublicKey2(address);
|
|
382
433
|
const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(publicKey, {
|
|
383
|
-
programId: new
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
1032
|
-
|
|
1033
|
-
|
|
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(
|
|
1087
|
+
instructions.push(SystemProgram2.transfer({ fromPubkey, toPubkey: programId, lamports: Number(executable.value) }));
|
|
1036
1088
|
}
|
|
1037
1089
|
return this.setTransactionDefaults(instructions, fromPubkey);
|
|
1038
1090
|
}
|
|
1039
|
-
|
|
1040
|
-
if (!action.
|
|
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 <
|
|
1043
|
-
const accountDef =
|
|
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
|
|
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
|
|
1072
|
-
const receiverPubkey = new
|
|
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
|
|
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 (!
|
|
1182
|
-
for (let idx = 0; idx <
|
|
1183
|
-
const accountDef =
|
|
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
|
|
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
|
|
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
|
|
1281
|
-
return this.setTransactionDefaults([
|
|
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
|
|
1291
|
-
const fromPubkey = new
|
|
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
|
|
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
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
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
|
|
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
|
|
1427
|
-
if (
|
|
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
|
|
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
|
|
1466
|
-
const receiverPubkey = new
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
2151
|
-
|
|
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
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
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
|
-
|
|
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;
|