@wallfree-dev/solana 0.13.43-beta.10 → 0.13.43-beta.12

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.
@@ -79,16 +79,192 @@ var SolanaProtocol_1 = require("./SolanaProtocol");
79
79
  // SPL Token Program ID
80
80
  var TOKEN_PROGRAM_ID = new solanaWeb3.PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
81
81
  var ASSOCIATED_TOKEN_PROGRAM_ID = new solanaWeb3.PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
82
- // Rent exemption for a token account (165 bytes) - approximately 0.00203928 SOL
83
- // This is the minimum balance required to keep a token account alive
84
- var TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS = 2039280;
82
+ var MEMO_PROGRAM_ID = new solanaWeb3.PublicKey('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr');
83
+ // Memo prefix for wallet address hints (used for offline ATA resolution in Vault)
84
+ var WALLET_HINT_PREFIX = 'wallet:';
85
+ // Token account size in bytes (for rent exemption calculation)
86
+ var TOKEN_ACCOUNT_SIZE = 165;
87
+ // Default fee constants (fallback when network queries fail)
88
+ var DEFAULT_BASE_FEE_LAMPORTS = 5000;
89
+ var DEFAULT_TOKEN_ACCOUNT_RENT = 2039280; // Fallback rent exemption
90
+ var DEFAULT_SPL_TRANSFER_CU = 30000; // Fallback CU for SPL transfer
91
+ var DEFAULT_ATA_CREATE_CU = 25000; // Fallback CU for ATA creation
92
+ // Cache TTL configuration
93
+ var RENT_EXEMPTION_CACHE_TTL = 300000; // 5 minutes
85
94
  // Implementation
86
95
  var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
87
96
  function SolanaSPLTokenProtocolImpl(options) {
88
97
  this.options = options;
98
+ // Caches
99
+ this.priorityFeeCache = { data: null, timestamp: 0 };
100
+ this.rentExemptionCache = { value: null, timestamp: 0 };
89
101
  this.units = options.units;
90
102
  this.mainUnit = options.mainUnit;
91
103
  }
104
+ // Get minimum balance for rent exemption for token accounts (dynamic)
105
+ SolanaSPLTokenProtocolImpl.prototype.getTokenAccountRentExemption = function () {
106
+ return __awaiter(this, void 0, void 0, function () {
107
+ var now, rentExemption, e_1;
108
+ var _this = this;
109
+ return __generator(this, function (_a) {
110
+ switch (_a.label) {
111
+ case 0:
112
+ now = Date.now();
113
+ if (this.rentExemptionCache.value !== null &&
114
+ (now - this.rentExemptionCache.timestamp) < RENT_EXEMPTION_CACHE_TTL) {
115
+ return [2 /*return*/, this.rentExemptionCache.value];
116
+ }
117
+ _a.label = 1;
118
+ case 1:
119
+ _a.trys.push([1, 3, , 4]);
120
+ return [4 /*yield*/, this.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () {
121
+ return __generator(this, function (_a) {
122
+ return [2 /*return*/, connection.getMinimumBalanceForRentExemption(TOKEN_ACCOUNT_SIZE)];
123
+ });
124
+ }); })];
125
+ case 2:
126
+ rentExemption = _a.sent();
127
+ this.rentExemptionCache = { value: rentExemption, timestamp: now };
128
+ return [2 /*return*/, rentExemption];
129
+ case 3:
130
+ e_1 = _a.sent();
131
+ console.warn('[solana-spl][getTokenAccountRentExemption] Failed, using default:', e_1);
132
+ return [2 /*return*/, DEFAULT_TOKEN_ACCOUNT_RENT];
133
+ case 4: return [2 /*return*/];
134
+ }
135
+ });
136
+ });
137
+ };
138
+ // Simulate a transaction to get actual compute units consumed
139
+ SolanaSPLTokenProtocolImpl.prototype.simulateTransaction = function (transaction) {
140
+ return __awaiter(this, void 0, void 0, function () {
141
+ var result, e_2;
142
+ var _this = this;
143
+ return __generator(this, function (_a) {
144
+ switch (_a.label) {
145
+ case 0:
146
+ _a.trys.push([0, 2, , 3]);
147
+ return [4 /*yield*/, this.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () {
148
+ var blockhash;
149
+ return __generator(this, function (_a) {
150
+ switch (_a.label) {
151
+ case 0:
152
+ if (!!transaction.recentBlockhash) return [3 /*break*/, 2];
153
+ return [4 /*yield*/, connection.getLatestBlockhash()];
154
+ case 1:
155
+ blockhash = (_a.sent()).blockhash;
156
+ transaction.recentBlockhash = blockhash;
157
+ _a.label = 2;
158
+ case 2:
159
+ // For legacy Transaction, use the simple overload without config
160
+ return [2 /*return*/, connection.simulateTransaction(transaction)];
161
+ }
162
+ });
163
+ }); })];
164
+ case 1:
165
+ result = _a.sent();
166
+ if (result.value.err) {
167
+ return [2 /*return*/, {
168
+ success: false,
169
+ unitsConsumed: 0,
170
+ error: JSON.stringify(result.value.err)
171
+ }];
172
+ }
173
+ return [2 /*return*/, {
174
+ success: true,
175
+ unitsConsumed: result.value.unitsConsumed || 0
176
+ }];
177
+ case 2:
178
+ e_2 = _a.sent();
179
+ console.warn('[solana-spl][simulateTransaction] Simulation failed:', e_2);
180
+ return [2 /*return*/, {
181
+ success: false,
182
+ unitsConsumed: 0,
183
+ error: String(e_2)
184
+ }];
185
+ case 3: return [2 /*return*/];
186
+ }
187
+ });
188
+ });
189
+ };
190
+ // Get recent priority fees from the network
191
+ SolanaSPLTokenProtocolImpl.prototype.getRecentPriorityFees = function () {
192
+ return __awaiter(this, void 0, void 0, function () {
193
+ var now, recentFees, allFeeValues, hasNonZeroFees, feeValues, getPercentile, estimate, e_3;
194
+ var _this = this;
195
+ return __generator(this, function (_a) {
196
+ switch (_a.label) {
197
+ case 0:
198
+ now = Date.now();
199
+ if (this.priorityFeeCache.data && (now - this.priorityFeeCache.timestamp) < SolanaSPLTokenProtocolImpl.PRIORITY_FEE_CACHE_TTL) {
200
+ return [2 /*return*/, this.priorityFeeCache.data];
201
+ }
202
+ _a.label = 1;
203
+ case 1:
204
+ _a.trys.push([1, 3, , 4]);
205
+ return [4 /*yield*/, this.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () {
206
+ return __generator(this, function (_a) {
207
+ return [2 /*return*/, connection.getRecentPrioritizationFees()];
208
+ });
209
+ }); })];
210
+ case 2:
211
+ recentFees = _a.sent();
212
+ if (!recentFees || recentFees.length === 0) {
213
+ return [2 /*return*/, this.getDefaultPriorityFees()];
214
+ }
215
+ allFeeValues = recentFees.map(function (f) { return f.prioritizationFee; });
216
+ hasNonZeroFees = allFeeValues.some(function (f) { return f > 0; });
217
+ if (!hasNonZeroFees) {
218
+ // Network is idle, no priority fee needed
219
+ return [2 /*return*/, {
220
+ none: 0,
221
+ low: 0,
222
+ medium: 0,
223
+ high: 0,
224
+ veryHigh: 0
225
+ }];
226
+ }
227
+ feeValues = allFeeValues
228
+ .filter(function (f) { return f > 0; })
229
+ .sort(function (a, b) { return a - b; });
230
+ if (feeValues.length === 0) {
231
+ return [2 /*return*/, this.getDefaultPriorityFees()];
232
+ }
233
+ getPercentile = function (arr, p) {
234
+ var index = Math.ceil((p / 100) * arr.length) - 1;
235
+ return arr[Math.max(0, Math.min(index, arr.length - 1))];
236
+ };
237
+ estimate = {
238
+ none: 0,
239
+ low: getPercentile(feeValues, 25),
240
+ medium: getPercentile(feeValues, 50),
241
+ high: getPercentile(feeValues, 75),
242
+ veryHigh: getPercentile(feeValues, 90)
243
+ };
244
+ this.priorityFeeCache = { data: estimate, timestamp: now };
245
+ return [2 /*return*/, estimate];
246
+ case 3:
247
+ e_3 = _a.sent();
248
+ console.warn('[solana-spl][getRecentPriorityFees] Failed:', e_3);
249
+ return [2 /*return*/, this.getDefaultPriorityFees()];
250
+ case 4: return [2 /*return*/];
251
+ }
252
+ });
253
+ });
254
+ };
255
+ SolanaSPLTokenProtocolImpl.prototype.getDefaultPriorityFees = function () {
256
+ return {
257
+ none: 0,
258
+ low: 1000,
259
+ medium: 10000,
260
+ high: 100000,
261
+ veryHigh: 1000000
262
+ };
263
+ };
264
+ SolanaSPLTokenProtocolImpl.prototype.calculateTotalFee = function (baseFee, priorityFeePerCU, computeUnits) {
265
+ var priorityFeeLamports = Math.ceil((computeUnits * priorityFeePerCU) / 1000000);
266
+ return baseFee + priorityFeeLamports;
267
+ };
92
268
  // Helper for RPC calls with fallback to backup endpoints
93
269
  SolanaSPLTokenProtocolImpl.prototype.withFallback = function (fn, maxRetries) {
94
270
  var _a, _b, _c, _d, _e;
@@ -105,7 +281,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
105
281
  if (!(_i < allUrls_1.length)) return [3 /*break*/, 6];
106
282
  rpcUrl = allUrls_1[_i];
107
283
  _loop_1 = function (retry) {
108
- var connection, _g, e_1, isTemporaryError;
284
+ var connection, _g, e_4, isTemporaryError;
109
285
  return __generator(this, function (_h) {
110
286
  switch (_h.label) {
111
287
  case 0:
@@ -115,13 +291,13 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
115
291
  return [4 /*yield*/, fn(connection)];
116
292
  case 1: return [2 /*return*/, (_g.value = _h.sent(), _g)];
117
293
  case 2:
118
- e_1 = _h.sent();
119
- lastError = e_1;
120
- isTemporaryError = ((_a = e_1 === null || e_1 === void 0 ? void 0 : e_1.message) === null || _a === void 0 ? void 0 : _a.includes('500')) ||
121
- ((_b = e_1 === null || e_1 === void 0 ? void 0 : e_1.message) === null || _b === void 0 ? void 0 : _b.includes('502')) ||
122
- ((_c = e_1 === null || e_1 === void 0 ? void 0 : e_1.message) === null || _c === void 0 ? void 0 : _c.includes('503')) ||
123
- ((_d = e_1 === null || e_1 === void 0 ? void 0 : e_1.message) === null || _d === void 0 ? void 0 : _d.includes('code":19')) ||
124
- ((_e = e_1 === null || e_1 === void 0 ? void 0 : e_1.message) === null || _e === void 0 ? void 0 : _e.includes('Temporary'));
294
+ e_4 = _h.sent();
295
+ lastError = e_4;
296
+ isTemporaryError = ((_a = e_4 === null || e_4 === void 0 ? void 0 : e_4.message) === null || _a === void 0 ? void 0 : _a.includes('500')) ||
297
+ ((_b = e_4 === null || e_4 === void 0 ? void 0 : e_4.message) === null || _b === void 0 ? void 0 : _b.includes('502')) ||
298
+ ((_c = e_4 === null || e_4 === void 0 ? void 0 : e_4.message) === null || _c === void 0 ? void 0 : _c.includes('503')) ||
299
+ ((_d = e_4 === null || e_4 === void 0 ? void 0 : e_4.message) === null || _d === void 0 ? void 0 : _d.includes('code":19')) ||
300
+ ((_e = e_4 === null || e_4 === void 0 ? void 0 : e_4.message) === null || _e === void 0 ? void 0 : _e.includes('Temporary'));
125
301
  if (!isTemporaryError) {
126
302
  return [2 /*return*/, "break"];
127
303
  }
@@ -285,7 +461,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
285
461
  // Returns the owner (wallet) address of a token account
286
462
  SolanaSPLTokenProtocolImpl.prototype.getWalletAddressFromAta = function (ataAddress) {
287
463
  return __awaiter(this, void 0, void 0, function () {
288
- var ataPubkey_1, accountInfo, ownerBytes, ownerPubkey, e_2;
464
+ var ataPubkey_1, accountInfo, ownerBytes, ownerPubkey, e_5;
289
465
  var _this = this;
290
466
  return __generator(this, function (_a) {
291
467
  switch (_a.label) {
@@ -304,8 +480,8 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
304
480
  ownerPubkey = new solanaWeb3.PublicKey(ownerBytes);
305
481
  return [2 /*return*/, ownerPubkey.toBase58()];
306
482
  case 2:
307
- e_2 = _a.sent();
308
- console.warn('[solana-spl][getWalletAddressFromAta] Failed to get wallet address:', e_2);
483
+ e_5 = _a.sent();
484
+ console.warn('[solana-spl][getWalletAddressFromAta] Failed to get wallet address:', e_5);
309
485
  return [2 /*return*/, null];
310
486
  case 3: return [2 /*return*/];
311
487
  }
@@ -314,7 +490,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
314
490
  };
315
491
  SolanaSPLTokenProtocolImpl.prototype.getBalanceOfAddress = function (address) {
316
492
  return __awaiter(this, void 0, void 0, function () {
317
- var walletPubkey_1, mintPubkey_1, tokenAccounts, totalBalance, _i, _a, account, data, amountBytes, amount, e_3;
493
+ var walletPubkey_1, mintPubkey_1, tokenAccounts, totalBalance, _i, _a, account, data, amountBytes, amount, e_6;
318
494
  var _this = this;
319
495
  return __generator(this, function (_b) {
320
496
  switch (_b.label) {
@@ -341,8 +517,8 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
341
517
  total: (0, module_kit_1.newAmount)(totalBalance.toString(), 'blockchain')
342
518
  }];
343
519
  case 2:
344
- e_3 = _b.sent();
345
- console.error('[solana-spl][balance][error]', e_3);
520
+ e_6 = _b.sent();
521
+ console.error('[solana-spl][balance][error]', e_6);
346
522
  return [2 /*return*/, { total: (0, module_kit_1.newAmount)(0, 'blockchain') }];
347
523
  case 3: return [2 /*return*/];
348
524
  }
@@ -379,106 +555,143 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
379
555
  });
380
556
  };
381
557
  SolanaSPLTokenProtocolImpl.prototype.getDetailsFromTransaction = function (transaction, publicKey) {
382
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
558
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
383
559
  return __awaiter(this, void 0, void 0, function () {
384
- var tx, fallbackFeePayer, _k, _l, _m, feePayer, fee, connection, feeInfo, e_4, _i, _o, ix, amountBytes, amount, destAta, ownerWallet, toWallet, resolvedWallet, _p, amountBytes, amount, destAta, ownerWallet, toWallet, resolvedWallet, _q, e_5;
385
- return __generator(this, function (_r) {
386
- switch (_r.label) {
560
+ var tx, fallbackFeePayer, _p, _q, _r, feePayer, fee, connection, feeInfo, e_7, ataToWalletMap_1, walletHints_1, _i, _s, ix, ataAddress, walletAddress, memoText, walletAddress, resolveAtaToWallet, _t, _u, ix, amountBytes, amount, destAta, ownerWallet, toWallet, amountBytes, amount, destAta, ownerWallet, toWallet, e_8;
561
+ var _this = this;
562
+ return __generator(this, function (_v) {
563
+ switch (_v.label) {
387
564
  case 0:
388
- _r.trys.push([0, 20, , 21]);
565
+ _v.trys.push([0, 14, , 15]);
389
566
  tx = solanaWeb3.Transaction.from(Buffer.from(transaction.serialized, 'hex'));
390
567
  if (!(publicKey !== null && publicKey !== undefined)) return [3 /*break*/, 2];
391
- _m = (_l = solanaWeb3.PublicKey).bind;
568
+ _r = (_q = solanaWeb3.PublicKey).bind;
392
569
  return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
393
570
  case 1:
394
- _k = new (_m.apply(_l, [void 0, _r.sent()]))();
571
+ _p = new (_r.apply(_q, [void 0, _v.sent()]))();
395
572
  return [3 /*break*/, 3];
396
573
  case 2:
397
- _k = undefined;
398
- _r.label = 3;
574
+ _p = undefined;
575
+ _v.label = 3;
399
576
  case 3:
400
- fallbackFeePayer = _k;
577
+ fallbackFeePayer = _p;
401
578
  feePayer = (tx === null || tx === void 0 ? void 0 : tx.feePayer) || (tx.signatures.length > 0 ? tx.signatures[0].publicKey : fallbackFeePayer);
402
579
  fee = (0, module_kit_1.newAmount)(5000, 'Lamports');
403
- _r.label = 4;
580
+ _v.label = 4;
404
581
  case 4:
405
- _r.trys.push([4, 6, , 7]);
582
+ _v.trys.push([4, 6, , 7]);
406
583
  connection = new solanaWeb3.Connection(this.options.network.rpcUrl);
407
584
  return [4 /*yield*/, connection.getFeeForMessage(tx.compileMessage())];
408
585
  case 5:
409
- feeInfo = _r.sent();
586
+ feeInfo = _v.sent();
410
587
  fee = (0, module_kit_1.newAmount)((_a = feeInfo === null || feeInfo === void 0 ? void 0 : feeInfo.value) !== null && _a !== void 0 ? _a : 5000, 'Lamports');
411
588
  return [3 /*break*/, 7];
412
589
  case 6:
413
- e_4 = _r.sent();
590
+ e_7 = _v.sent();
414
591
  console.warn('[solana-spl][getDetailsFromTransaction] Network unavailable, using default fee');
415
592
  return [3 /*break*/, 7];
416
593
  case 7:
417
- _i = 0, _o = tx.instructions;
418
- _r.label = 8;
594
+ ataToWalletMap_1 = new Map();
595
+ walletHints_1 = [];
596
+ for (_i = 0, _s = tx.instructions; _i < _s.length; _i++) {
597
+ ix = _s[_i];
598
+ if (ix.programId.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
599
+ ataAddress = (_c = (_b = ix.keys[1]) === null || _b === void 0 ? void 0 : _b.pubkey) === null || _c === void 0 ? void 0 : _c.toBase58();
600
+ walletAddress = (_e = (_d = ix.keys[2]) === null || _d === void 0 ? void 0 : _d.pubkey) === null || _e === void 0 ? void 0 : _e.toBase58();
601
+ if (ataAddress && walletAddress) {
602
+ ataToWalletMap_1.set(ataAddress, walletAddress);
603
+ }
604
+ }
605
+ // Parse memo instructions for wallet hints
606
+ if (ix.programId.equals(MEMO_PROGRAM_ID)) {
607
+ try {
608
+ memoText = Buffer.from(ix.data).toString('utf-8');
609
+ if (memoText.startsWith(WALLET_HINT_PREFIX)) {
610
+ walletAddress = memoText.slice(WALLET_HINT_PREFIX.length);
611
+ walletHints_1.push(walletAddress);
612
+ }
613
+ }
614
+ catch (_w) {
615
+ // Ignore memo parsing errors
616
+ }
617
+ }
618
+ }
619
+ resolveAtaToWallet = function (ataAddress, hintIndex) {
620
+ if (hintIndex === void 0) { hintIndex = 0; }
621
+ return __awaiter(_this, void 0, void 0, function () {
622
+ var resolvedWallet, _a;
623
+ return __generator(this, function (_b) {
624
+ switch (_b.label) {
625
+ case 0:
626
+ // First check if we found it in ATA creation instructions (works offline)
627
+ if (ataToWalletMap_1.has(ataAddress)) {
628
+ return [2 /*return*/, ataToWalletMap_1.get(ataAddress)];
629
+ }
630
+ // Check if we have a wallet hint from memo (works offline)
631
+ if (walletHints_1.length > hintIndex && walletHints_1[hintIndex]) {
632
+ return [2 /*return*/, walletHints_1[hintIndex]];
633
+ }
634
+ _b.label = 1;
635
+ case 1:
636
+ _b.trys.push([1, 3, , 4]);
637
+ return [4 /*yield*/, this.getWalletAddressFromAta(ataAddress)];
638
+ case 2:
639
+ resolvedWallet = _b.sent();
640
+ if (resolvedWallet) {
641
+ return [2 /*return*/, resolvedWallet];
642
+ }
643
+ return [3 /*break*/, 4];
644
+ case 3:
645
+ _a = _b.sent();
646
+ return [3 /*break*/, 4];
647
+ case 4: return [2 /*return*/, ataAddress]; // Return ATA address if all resolution fails
648
+ }
649
+ });
650
+ });
651
+ };
652
+ _t = 0, _u = tx.instructions;
653
+ _v.label = 8;
419
654
  case 8:
420
- if (!(_i < _o.length)) return [3 /*break*/, 19];
421
- ix = _o[_i];
422
- if (!ix.programId.equals(TOKEN_PROGRAM_ID)) return [3 /*break*/, 18];
423
- if (!(ix.data.length >= 9 && ix.data[0] === 3)) return [3 /*break*/, 13];
655
+ if (!(_t < _u.length)) return [3 /*break*/, 13];
656
+ ix = _u[_t];
657
+ if (!ix.programId.equals(TOKEN_PROGRAM_ID)) return [3 /*break*/, 12];
658
+ if (!(ix.data.length >= 9 && ix.data[0] === 3)) return [3 /*break*/, 10];
424
659
  amountBytes = ix.data.slice(1, 9);
425
660
  amount = this.readU64LE(amountBytes).toString();
426
- destAta = ((_c = (_b = ix.keys[1]) === null || _b === void 0 ? void 0 : _b.pubkey) === null || _c === void 0 ? void 0 : _c.toBase58()) || '';
427
- ownerWallet = ((_e = (_d = ix.keys[2]) === null || _d === void 0 ? void 0 : _d.pubkey) === null || _e === void 0 ? void 0 : _e.toBase58()) || (feePayer === null || feePayer === void 0 ? void 0 : feePayer.toBase58()) || '';
428
- toWallet = destAta;
429
- _r.label = 9;
661
+ destAta = ((_g = (_f = ix.keys[1]) === null || _f === void 0 ? void 0 : _f.pubkey) === null || _g === void 0 ? void 0 : _g.toBase58()) || '';
662
+ ownerWallet = ((_j = (_h = ix.keys[2]) === null || _h === void 0 ? void 0 : _h.pubkey) === null || _j === void 0 ? void 0 : _j.toBase58()) || (feePayer === null || feePayer === void 0 ? void 0 : feePayer.toBase58()) || '';
663
+ return [4 /*yield*/, resolveAtaToWallet(destAta)];
430
664
  case 9:
431
- _r.trys.push([9, 11, , 12]);
432
- return [4 /*yield*/, this.getWalletAddressFromAta(destAta)];
665
+ toWallet = _v.sent();
666
+ return [2 /*return*/, [{
667
+ from: [ownerWallet],
668
+ to: [toWallet],
669
+ amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
670
+ fee: fee,
671
+ isInbound: false,
672
+ network: this.options.network
673
+ }]];
433
674
  case 10:
434
- resolvedWallet = _r.sent();
435
- if (resolvedWallet) {
436
- toWallet = resolvedWallet;
437
- }
438
- return [3 /*break*/, 12];
439
- case 11:
440
- _p = _r.sent();
441
- return [3 /*break*/, 12];
442
- case 12: return [2 /*return*/, [{
443
- from: [ownerWallet],
444
- to: [toWallet],
445
- amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
446
- fee: fee,
447
- isInbound: false,
448
- network: this.options.network
449
- }]];
450
- case 13:
451
- if (!(ix.data.length >= 10 && ix.data[0] === 12)) return [3 /*break*/, 18];
675
+ if (!(ix.data.length >= 10 && ix.data[0] === 12)) return [3 /*break*/, 12];
452
676
  amountBytes = ix.data.slice(1, 9);
453
677
  amount = this.readU64LE(amountBytes).toString();
454
- destAta = ((_g = (_f = ix.keys[2]) === null || _f === void 0 ? void 0 : _f.pubkey) === null || _g === void 0 ? void 0 : _g.toBase58()) || '';
455
- ownerWallet = ((_j = (_h = ix.keys[3]) === null || _h === void 0 ? void 0 : _h.pubkey) === null || _j === void 0 ? void 0 : _j.toBase58()) || (feePayer === null || feePayer === void 0 ? void 0 : feePayer.toBase58()) || '';
456
- toWallet = destAta;
457
- _r.label = 14;
458
- case 14:
459
- _r.trys.push([14, 16, , 17]);
460
- return [4 /*yield*/, this.getWalletAddressFromAta(destAta)];
461
- case 15:
462
- resolvedWallet = _r.sent();
463
- if (resolvedWallet) {
464
- toWallet = resolvedWallet;
465
- }
466
- return [3 /*break*/, 17];
467
- case 16:
468
- _q = _r.sent();
469
- return [3 /*break*/, 17];
470
- case 17: return [2 /*return*/, [{
471
- from: [ownerWallet],
472
- to: [toWallet],
473
- amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
474
- fee: fee,
475
- isInbound: false,
476
- network: this.options.network
477
- }]];
478
- case 18:
479
- _i++;
678
+ destAta = ((_l = (_k = ix.keys[2]) === null || _k === void 0 ? void 0 : _k.pubkey) === null || _l === void 0 ? void 0 : _l.toBase58()) || '';
679
+ ownerWallet = ((_o = (_m = ix.keys[3]) === null || _m === void 0 ? void 0 : _m.pubkey) === null || _o === void 0 ? void 0 : _o.toBase58()) || (feePayer === null || feePayer === void 0 ? void 0 : feePayer.toBase58()) || '';
680
+ return [4 /*yield*/, resolveAtaToWallet(destAta)];
681
+ case 11:
682
+ toWallet = _v.sent();
683
+ return [2 /*return*/, [{
684
+ from: [ownerWallet],
685
+ to: [toWallet],
686
+ amount: (0, module_kit_1.newAmount)(amount, 'blockchain'),
687
+ fee: fee,
688
+ isInbound: false,
689
+ network: this.options.network
690
+ }]];
691
+ case 12:
692
+ _t++;
480
693
  return [3 /*break*/, 8];
481
- case 19:
694
+ case 13:
482
695
  // Fallback
483
696
  return [2 /*return*/, [{
484
697
  from: [(feePayer === null || feePayer === void 0 ? void 0 : feePayer.toBase58()) || ''],
@@ -488,9 +701,9 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
488
701
  isInbound: false,
489
702
  network: this.options.network
490
703
  }]];
491
- case 20:
492
- e_5 = _r.sent();
493
- console.error('[solana-spl][getDetailsFromTransaction] Failed:', e_5);
704
+ case 14:
705
+ e_8 = _v.sent();
706
+ console.error('[solana-spl][getDetailsFromTransaction] Failed:', e_8);
494
707
  return [2 /*return*/, [{
495
708
  from: [],
496
709
  to: [],
@@ -499,7 +712,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
499
712
  isInbound: false,
500
713
  network: this.options.network
501
714
  }]];
502
- case 21: return [2 /*return*/];
715
+ case 15: return [2 /*return*/];
503
716
  }
504
717
  });
505
718
  });
@@ -641,14 +854,14 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
641
854
  });
642
855
  };
643
856
  SolanaSPLTokenProtocolImpl.prototype.getTransactionsForAddress = function (address, limit, cursor) {
644
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
857
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
645
858
  return __awaiter(this, void 0, void 0, function () {
646
- var walletPubkey_2, mintPubkey_2, effectiveLimit, tokenAccounts, txs, myAtaAddresses, _i, _k, pubkey, queryOptions_1, allSignatures, _loop_2, this_1, _l, _m, tokenAccountPubkey, uniqueSignatures, limitedSignatures, _loop_3, this_2, _o, limitedSignatures_1, sigInfo, hasNext, lastSignature, newCursor, e_6;
859
+ var walletPubkey_2, mintPubkey_2, effectiveLimit, tokenAccounts, txs, myAtaAddresses, _i, _u, pubkey, queryOptions_1, allSignatures, _loop_2, this_1, _v, _w, tokenAccountPubkey, uniqueSignatures, limitedSignatures, _loop_3, this_2, _x, limitedSignatures_1, sigInfo, hasNext, lastSignature, newCursor, e_9;
647
860
  var _this = this;
648
- return __generator(this, function (_p) {
649
- switch (_p.label) {
861
+ return __generator(this, function (_y) {
862
+ switch (_y.label) {
650
863
  case 0:
651
- _p.trys.push([0, 10, , 11]);
864
+ _y.trys.push([0, 10, , 11]);
652
865
  walletPubkey_2 = new solanaWeb3.PublicKey(address);
653
866
  mintPubkey_2 = new solanaWeb3.PublicKey(this.options.contractAddress);
654
867
  effectiveLimit = limit || SolanaSPLTokenProtocolImpl.DEFAULT_TX_LIMIT;
@@ -656,7 +869,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
656
869
  return [2 /*return*/, connection.getTokenAccountsByOwner(walletPubkey_2, { mint: mintPubkey_2 })];
657
870
  }); }); })];
658
871
  case 1:
659
- tokenAccounts = _p.sent();
872
+ tokenAccounts = _y.sent();
660
873
  if (tokenAccounts.value.length === 0) {
661
874
  return [2 /*return*/, {
662
875
  transactions: [],
@@ -665,8 +878,8 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
665
878
  }
666
879
  txs = [];
667
880
  myAtaAddresses = new Set();
668
- for (_i = 0, _k = tokenAccounts.value; _i < _k.length; _i++) {
669
- pubkey = _k[_i].pubkey;
881
+ for (_i = 0, _u = tokenAccounts.value; _i < _u.length; _i++) {
882
+ pubkey = _u[_i].pubkey;
670
883
  myAtaAddresses.add(pubkey.toBase58());
671
884
  }
672
885
  queryOptions_1 = {
@@ -678,16 +891,16 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
678
891
  }
679
892
  allSignatures = [];
680
893
  _loop_2 = function (tokenAccountPubkey) {
681
- var signatures, _q, signatures_1, sig;
682
- return __generator(this, function (_r) {
683
- switch (_r.label) {
894
+ var signatures, _z, signatures_1, sig;
895
+ return __generator(this, function (_0) {
896
+ switch (_0.label) {
684
897
  case 0: return [4 /*yield*/, this_1.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
685
898
  return [2 /*return*/, connection.getSignaturesForAddress(tokenAccountPubkey, queryOptions_1)];
686
899
  }); }); })];
687
900
  case 1:
688
- signatures = _r.sent();
689
- for (_q = 0, signatures_1 = signatures; _q < signatures_1.length; _q++) {
690
- sig = signatures_1[_q];
901
+ signatures = _0.sent();
902
+ for (_z = 0, signatures_1 = signatures; _z < signatures_1.length; _z++) {
903
+ sig = signatures_1[_z];
691
904
  if (sig.signature) {
692
905
  allSignatures.push({
693
906
  signature: sig.signature,
@@ -701,17 +914,17 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
701
914
  });
702
915
  };
703
916
  this_1 = this;
704
- _l = 0, _m = tokenAccounts.value;
705
- _p.label = 2;
917
+ _v = 0, _w = tokenAccounts.value;
918
+ _y.label = 2;
706
919
  case 2:
707
- if (!(_l < _m.length)) return [3 /*break*/, 5];
708
- tokenAccountPubkey = _m[_l].pubkey;
920
+ if (!(_v < _w.length)) return [3 /*break*/, 5];
921
+ tokenAccountPubkey = _w[_v].pubkey;
709
922
  return [5 /*yield**/, _loop_2(tokenAccountPubkey)];
710
923
  case 3:
711
- _p.sent();
712
- _p.label = 4;
924
+ _y.sent();
925
+ _y.label = 4;
713
926
  case 4:
714
- _l++;
927
+ _v++;
715
928
  return [3 /*break*/, 2];
716
929
  case 5:
717
930
  uniqueSignatures = Array.from(new Map(allSignatures.map(function (s) { return [s.signature, s]; })).values());
@@ -719,11 +932,11 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
719
932
  uniqueSignatures.sort(function (a, b) { return (b.blockTime || 0) - (a.blockTime || 0); });
720
933
  limitedSignatures = uniqueSignatures.slice(0, effectiveLimit);
721
934
  _loop_3 = function (sigInfo) {
722
- var parsed, amount, fromWallet, toWallet, isInbound, instructions, _s, instructions_1, ix, parsedIx, info, sourceAta, destAta, authorityWallet, resolvedFrom, resolvedTo, blockTime, timestamp, e_7;
723
- return __generator(this, function (_t) {
724
- switch (_t.label) {
935
+ var parsed, amount, fromWallet, toWallet, isInbound, foundTransfer, ataToWalletMap_2, instructions, _1, instructions_1, ix, parsedIx, info, innerInstructions, _2, innerInstructions_1, innerGroup, _3, _4, innerIx, parsedIx, info, resolveAtaToWallet, _5, instructions_2, ix, parsedIx, info, txMint, sourceAta, destAta, authorityWallet, isSourceMine, isDestMine, resolvedFrom, resolvedTo, resolvedTo, accountKeys, accountAddresses, resolvedTo, blockTime, timestamp, e_10;
936
+ return __generator(this, function (_6) {
937
+ switch (_6.label) {
725
938
  case 0:
726
- _t.trys.push([0, 11, , 12]);
939
+ _6.trys.push([0, 17, , 18]);
727
940
  return [4 /*yield*/, this_2.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () {
728
941
  return __generator(this, function (_a) {
729
942
  return [2 /*return*/, connection.getParsedTransaction(sigInfo.signature, {
@@ -733,94 +946,181 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
733
946
  });
734
947
  }); })];
735
948
  case 1:
736
- parsed = _t.sent();
949
+ parsed = _6.sent();
737
950
  if (!parsed)
738
951
  return [2 /*return*/, "continue"];
739
952
  amount = (0, module_kit_1.newAmount)(0, 'blockchain');
740
953
  fromWallet = address;
741
954
  toWallet = address;
742
955
  isInbound = false;
956
+ foundTransfer = false;
957
+ ataToWalletMap_2 = new Map();
743
958
  instructions = ((_b = (_a = parsed.transaction) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.instructions) || [];
744
- _s = 0, instructions_1 = instructions;
745
- _t.label = 2;
959
+ for (_1 = 0, instructions_1 = instructions; _1 < instructions_1.length; _1++) {
960
+ ix = instructions_1[_1];
961
+ if ('parsed' in ix && ix.parsed) {
962
+ parsedIx = ix;
963
+ // Look for ATA creation by Associated Token Program
964
+ if (parsedIx.program === 'spl-associated-token-account' &&
965
+ (((_c = parsedIx.parsed) === null || _c === void 0 ? void 0 : _c.type) === 'create' || ((_d = parsedIx.parsed) === null || _d === void 0 ? void 0 : _d.type) === 'createIdempotent')) {
966
+ info = (_e = parsedIx.parsed) === null || _e === void 0 ? void 0 : _e.info;
967
+ if ((info === null || info === void 0 ? void 0 : info.account) && (info === null || info === void 0 ? void 0 : info.wallet)) {
968
+ // Map ATA address to wallet address
969
+ ataToWalletMap_2.set(info.account, info.wallet);
970
+ }
971
+ }
972
+ }
973
+ }
974
+ innerInstructions = ((_f = parsed.meta) === null || _f === void 0 ? void 0 : _f.innerInstructions) || [];
975
+ for (_2 = 0, innerInstructions_1 = innerInstructions; _2 < innerInstructions_1.length; _2++) {
976
+ innerGroup = innerInstructions_1[_2];
977
+ for (_3 = 0, _4 = innerGroup.instructions || []; _3 < _4.length; _3++) {
978
+ innerIx = _4[_3];
979
+ if ('parsed' in innerIx && innerIx.parsed) {
980
+ parsedIx = innerIx;
981
+ if (parsedIx.program === 'spl-associated-token-account' &&
982
+ (((_g = parsedIx.parsed) === null || _g === void 0 ? void 0 : _g.type) === 'create' || ((_h = parsedIx.parsed) === null || _h === void 0 ? void 0 : _h.type) === 'createIdempotent')) {
983
+ info = (_j = parsedIx.parsed) === null || _j === void 0 ? void 0 : _j.info;
984
+ if ((info === null || info === void 0 ? void 0 : info.account) && (info === null || info === void 0 ? void 0 : info.wallet)) {
985
+ ataToWalletMap_2.set(info.account, info.wallet);
986
+ }
987
+ }
988
+ }
989
+ }
990
+ }
991
+ resolveAtaToWallet = function (ataAddress) { return __awaiter(_this, void 0, void 0, function () {
992
+ return __generator(this, function (_a) {
993
+ // First check local map from ATA creation instructions
994
+ if (ataToWalletMap_2.has(ataAddress)) {
995
+ return [2 /*return*/, ataToWalletMap_2.get(ataAddress)];
996
+ }
997
+ // Fall back to network query
998
+ return [2 /*return*/, this.getWalletAddressFromAta(ataAddress).catch(function () { return null; })];
999
+ });
1000
+ }); };
1001
+ _5 = 0, instructions_2 = instructions;
1002
+ _6.label = 2;
746
1003
  case 2:
747
- if (!(_s < instructions_1.length)) return [3 /*break*/, 10];
748
- ix = instructions_1[_s];
749
- if (!('parsed' in ix && ix.parsed)) return [3 /*break*/, 9];
1004
+ if (!(_5 < instructions_2.length)) return [3 /*break*/, 16];
1005
+ ix = instructions_2[_5];
1006
+ if (!('parsed' in ix && ix.parsed)) return [3 /*break*/, 15];
750
1007
  parsedIx = ix;
751
- if (!(parsedIx.program === 'spl-token')) return [3 /*break*/, 9];
752
- info = (_c = parsedIx.parsed) === null || _c === void 0 ? void 0 : _c.info;
753
- if (!(((_d = parsedIx.parsed) === null || _d === void 0 ? void 0 : _d.type) === 'transfer' || ((_e = parsedIx.parsed) === null || _e === void 0 ? void 0 : _e.type) === 'transferChecked')) return [3 /*break*/, 9];
754
- if (!((info === null || info === void 0 ? void 0 : info.mint) === this_2.options.contractAddress || !(info === null || info === void 0 ? void 0 : info.mint))) return [3 /*break*/, 9];
755
- amount = (0, module_kit_1.newAmount)((info === null || info === void 0 ? void 0 : info.amount) || ((_f = info === null || info === void 0 ? void 0 : info.tokenAmount) === null || _f === void 0 ? void 0 : _f.amount) || '0', 'blockchain');
1008
+ if (!(parsedIx.program === 'spl-token')) return [3 /*break*/, 15];
1009
+ info = (_k = parsedIx.parsed) === null || _k === void 0 ? void 0 : _k.info;
1010
+ if (!(((_l = parsedIx.parsed) === null || _l === void 0 ? void 0 : _l.type) === 'transfer' || ((_m = parsedIx.parsed) === null || _m === void 0 ? void 0 : _m.type) === 'transferChecked')) return [3 /*break*/, 15];
1011
+ txMint = info === null || info === void 0 ? void 0 : info.mint;
1012
+ if (!(txMint === this_2.options.contractAddress || !txMint)) return [3 /*break*/, 15];
1013
+ foundTransfer = true;
1014
+ amount = (0, module_kit_1.newAmount)((info === null || info === void 0 ? void 0 : info.amount) || ((_o = info === null || info === void 0 ? void 0 : info.tokenAmount) === null || _o === void 0 ? void 0 : _o.amount) || '0', 'blockchain');
756
1015
  sourceAta = (info === null || info === void 0 ? void 0 : info.source) || '';
757
1016
  destAta = (info === null || info === void 0 ? void 0 : info.destination) || '';
758
1017
  authorityWallet = (info === null || info === void 0 ? void 0 : info.authority) || '';
759
- // Determine if this is inbound or outbound based on ATA ownership
760
- isInbound = myAtaAddresses.has(destAta) && !myAtaAddresses.has(sourceAta);
761
- if (!isInbound) return [3 /*break*/, 6];
762
- // Inbound: we received tokens
763
- // from = sender's wallet (need to resolve from source ATA)
764
- // to = our wallet address
765
- toWallet = address;
1018
+ isSourceMine = myAtaAddresses.has(sourceAta);
1019
+ isDestMine = myAtaAddresses.has(destAta);
1020
+ if (!(isDestMine && !isSourceMine)) return [3 /*break*/, 6];
1021
+ // Clear inbound: destination is mine, source is not
1022
+ isInbound = true;
1023
+ toWallet = address; // Always use our wallet address for 'to'
766
1024
  if (!authorityWallet) return [3 /*break*/, 3];
767
1025
  fromWallet = authorityWallet;
768
1026
  return [3 /*break*/, 5];
769
- case 3: return [4 /*yield*/, this_2.getWalletAddressFromAta(sourceAta).catch(function () { return null; })];
1027
+ case 3: return [4 /*yield*/, resolveAtaToWallet(sourceAta)];
770
1028
  case 4:
771
- resolvedFrom = _t.sent();
1029
+ resolvedFrom = _6.sent();
772
1030
  fromWallet = resolvedFrom || sourceAta;
773
- _t.label = 5;
774
- case 5: return [3 /*break*/, 8];
1031
+ _6.label = 5;
1032
+ case 5: return [3 /*break*/, 14];
775
1033
  case 6:
776
- // Outbound: we sent tokens
777
- // from = our wallet address
778
- // to = recipient's wallet (need to resolve from dest ATA)
779
- fromWallet = authorityWallet || address;
780
- return [4 /*yield*/, this_2.getWalletAddressFromAta(destAta).catch(function () { return null; })];
1034
+ if (!(isSourceMine && !isDestMine)) return [3 /*break*/, 8];
1035
+ // Clear outbound: source is mine, destination is not
1036
+ isInbound = false;
1037
+ fromWallet = address; // Always use our wallet address for 'from'
1038
+ return [4 /*yield*/, resolveAtaToWallet(destAta)];
781
1039
  case 7:
782
- resolvedTo = _t.sent();
1040
+ resolvedTo = _6.sent();
783
1041
  toWallet = resolvedTo || destAta;
784
- _t.label = 8;
785
- case 8: return [3 /*break*/, 10];
1042
+ return [3 /*break*/, 14];
1043
+ case 8:
1044
+ if (!(isSourceMine && isDestMine)) return [3 /*break*/, 9];
1045
+ // Internal transfer (both are mine) - treat as outbound
1046
+ isInbound = false;
1047
+ fromWallet = address;
1048
+ toWallet = address;
1049
+ return [3 /*break*/, 14];
786
1050
  case 9:
787
- _s++;
788
- return [3 /*break*/, 2];
1051
+ if (!(authorityWallet === address)) return [3 /*break*/, 11];
1052
+ // User is the signer, so this is outbound
1053
+ isInbound = false;
1054
+ fromWallet = address;
1055
+ return [4 /*yield*/, resolveAtaToWallet(destAta)];
789
1056
  case 10:
790
- blockTime = (_g = sigInfo.blockTime) !== null && _g !== void 0 ? _g : parsed.blockTime;
1057
+ resolvedTo = _6.sent();
1058
+ toWallet = resolvedTo || destAta;
1059
+ return [3 /*break*/, 14];
1060
+ case 11:
1061
+ accountKeys = ((_q = (_p = parsed.transaction) === null || _p === void 0 ? void 0 : _p.message) === null || _q === void 0 ? void 0 : _q.accountKeys) || [];
1062
+ accountAddresses = accountKeys.map(function (k) { var _a; return typeof k === 'string' ? k : (((_a = k.pubkey) === null || _a === void 0 ? void 0 : _a.toString()) || k.toString()); });
1063
+ if (!accountAddresses.includes(address)) return [3 /*break*/, 13];
1064
+ // Our address is involved somewhere
1065
+ // Default to treating as relevant, use available info
1066
+ if (authorityWallet) {
1067
+ fromWallet = authorityWallet;
1068
+ }
1069
+ return [4 /*yield*/, resolveAtaToWallet(destAta)];
1070
+ case 12:
1071
+ resolvedTo = _6.sent();
1072
+ toWallet = resolvedTo || destAta;
1073
+ // Determine direction by checking if we're source or dest
1074
+ isInbound = toWallet === address;
1075
+ return [3 /*break*/, 14];
1076
+ case 13:
1077
+ // Transaction doesn't seem to involve our wallet directly
1078
+ // Skip this transaction
1079
+ foundTransfer = false;
1080
+ _6.label = 14;
1081
+ case 14: return [3 /*break*/, 16];
1082
+ case 15:
1083
+ _5++;
1084
+ return [3 /*break*/, 2];
1085
+ case 16:
1086
+ // Skip transactions that don't have a valid transfer for this token
1087
+ if (!foundTransfer) {
1088
+ return [2 /*return*/, "continue"];
1089
+ }
1090
+ blockTime = (_r = sigInfo.blockTime) !== null && _r !== void 0 ? _r : parsed.blockTime;
791
1091
  timestamp = blockTime ? blockTime : Math.floor(Date.now() / 1000);
792
1092
  txs.push({
793
1093
  hash: sigInfo.signature,
794
1094
  timestamp: timestamp,
795
1095
  status: sigInfo.confirmationStatus || 'processed',
796
1096
  amount: amount,
797
- fee: (0, module_kit_1.newAmount)((_j = (_h = parsed.meta) === null || _h === void 0 ? void 0 : _h.fee) !== null && _j !== void 0 ? _j : 0, 'Lamports'),
1097
+ fee: (0, module_kit_1.newAmount)((_t = (_s = parsed.meta) === null || _s === void 0 ? void 0 : _s.fee) !== null && _t !== void 0 ? _t : 0, 'Lamports'),
798
1098
  from: [fromWallet],
799
1099
  to: [toWallet],
800
1100
  isInbound: isInbound,
801
1101
  network: this_2.options.network
802
1102
  });
803
- return [3 /*break*/, 12];
804
- case 11:
805
- e_7 = _t.sent();
1103
+ return [3 /*break*/, 18];
1104
+ case 17:
1105
+ e_10 = _6.sent();
806
1106
  console.warn('[solana-spl][getTransactionsForAddress] Failed to parse tx:', sigInfo.signature);
807
- return [3 /*break*/, 12];
808
- case 12: return [2 /*return*/];
1107
+ return [3 /*break*/, 18];
1108
+ case 18: return [2 /*return*/];
809
1109
  }
810
1110
  });
811
1111
  };
812
1112
  this_2 = this;
813
- _o = 0, limitedSignatures_1 = limitedSignatures;
814
- _p.label = 6;
1113
+ _x = 0, limitedSignatures_1 = limitedSignatures;
1114
+ _y.label = 6;
815
1115
  case 6:
816
- if (!(_o < limitedSignatures_1.length)) return [3 /*break*/, 9];
817
- sigInfo = limitedSignatures_1[_o];
1116
+ if (!(_x < limitedSignatures_1.length)) return [3 /*break*/, 9];
1117
+ sigInfo = limitedSignatures_1[_x];
818
1118
  return [5 /*yield**/, _loop_3(sigInfo)];
819
1119
  case 7:
820
- _p.sent();
821
- _p.label = 8;
1120
+ _y.sent();
1121
+ _y.label = 8;
822
1122
  case 8:
823
- _o++;
1123
+ _x++;
824
1124
  return [3 /*break*/, 6];
825
1125
  case 9:
826
1126
  hasNext = limitedSignatures.length === effectiveLimit;
@@ -834,8 +1134,8 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
834
1134
  cursor: newCursor
835
1135
  }];
836
1136
  case 10:
837
- e_6 = _p.sent();
838
- console.error('[solana-spl][getTransactionsForAddress] Failed:', e_6);
1137
+ e_9 = _y.sent();
1138
+ console.error('[solana-spl][getTransactionsForAddress] Failed:', e_9);
839
1139
  return [2 /*return*/, {
840
1140
  transactions: [],
841
1141
  cursor: { hasNext: false }
@@ -901,20 +1201,32 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
901
1201
  };
902
1202
  SolanaSPLTokenProtocolImpl.prototype.getTransactionFeeWithPublicKey = function (publicKey, details, configuration) {
903
1203
  return __awaiter(this, void 0, void 0, function () {
904
- var baseFee, totalAtaCreationCost, mintPubkey, _loop_4, this_3, _i, details_1, detail, e_8, totalFee;
1204
+ var fromAddress, fromPubkey, mintPubkey, rentExemption, totalAtaCreationCost, ataCreationCount, ataCheckFailed, simulationTx, sourceAta, _loop_4, this_3, _i, details_1, detail, e_11, baseFee, feeResult, e_12, computeUnits, simulation, e_13, priorityFees, baseOnly, baseWithAta, lowFee, mediumFee, highFee, potentialAtaCost;
905
1205
  var _this = this;
906
1206
  return __generator(this, function (_a) {
907
1207
  switch (_a.label) {
908
- case 0:
909
- baseFee = 5000 // lamports
910
- ;
911
- totalAtaCreationCost = 0;
912
- _a.label = 1;
1208
+ case 0: return [4 /*yield*/, this.getAddressFromPublicKey(publicKey)];
913
1209
  case 1:
914
- _a.trys.push([1, 6, , 7]);
1210
+ fromAddress = _a.sent();
1211
+ fromPubkey = new solanaWeb3.PublicKey(fromAddress);
915
1212
  mintPubkey = new solanaWeb3.PublicKey(this.options.contractAddress);
1213
+ return [4 /*yield*/, this.getTokenAccountRentExemption()
1214
+ // Check if any destination requires ATA creation and build transaction for simulation
1215
+ ];
1216
+ case 2:
1217
+ rentExemption = _a.sent();
1218
+ totalAtaCreationCost = 0;
1219
+ ataCreationCount = 0;
1220
+ ataCheckFailed = false;
1221
+ simulationTx = new solanaWeb3.Transaction();
1222
+ _a.label = 3;
1223
+ case 3:
1224
+ _a.trys.push([3, 9, , 10]);
1225
+ return [4 /*yield*/, this.getAssociatedTokenAddress(fromAddress)];
1226
+ case 4:
1227
+ sourceAta = _a.sent();
916
1228
  _loop_4 = function (detail) {
917
- var toPubkey, destAta, destAtaInfo;
1229
+ var toPubkey, destAta, destAtaExists, ataQuerySuccess, destAtaInfo, e_14, amount;
918
1230
  return __generator(this, function (_b) {
919
1231
  switch (_b.label) {
920
1232
  case 0:
@@ -925,48 +1237,136 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
925
1237
  mintPubkey.toBuffer()
926
1238
  ], ASSOCIATED_TOKEN_PROGRAM_ID)
927
1239
  // Check if destination ATA exists
1240
+ // Important: distinguish between "ATA doesn't exist" (null result) and "query failed" (exception)
928
1241
  ];
929
1242
  case 1:
930
1243
  destAta = (_b.sent())[0];
1244
+ destAtaExists = false;
1245
+ ataQuerySuccess = false;
1246
+ _b.label = 2;
1247
+ case 2:
1248
+ _b.trys.push([2, 4, , 5]);
931
1249
  return [4 /*yield*/, this_3.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
932
1250
  return [2 /*return*/, connection.getAccountInfo(destAta)];
933
- }); }); }).catch(function () { return null; })];
934
- case 2:
1251
+ }); }); })];
1252
+ case 3:
935
1253
  destAtaInfo = _b.sent();
936
- if (!destAtaInfo) {
937
- // ATA doesn't exist, need to pay rent exemption to create it
938
- totalAtaCreationCost += TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS;
1254
+ ataQuerySuccess = true;
1255
+ destAtaExists = destAtaInfo !== null;
1256
+ return [3 /*break*/, 5];
1257
+ case 4:
1258
+ e_14 = _b.sent();
1259
+ console.warn('[solana-spl][getTransactionFeeWithPublicKey] ATA query failed for:', detail.to);
1260
+ ataCheckFailed = true;
1261
+ return [3 /*break*/, 5];
1262
+ case 5:
1263
+ if (ataQuerySuccess && !destAtaExists) {
1264
+ // ATA confirmed to not exist, need to create it
1265
+ totalAtaCreationCost += rentExemption;
1266
+ ataCreationCount++;
1267
+ // Add ATA creation instruction for simulation
1268
+ simulationTx.add(this_3.createAssociatedTokenAccountInstruction(fromPubkey, destAta, toPubkey, mintPubkey));
939
1269
  }
1270
+ amount = new bignumber_1.BigNumber((0, module_kit_1.newAmount)(detail.amount).blockchain(this_3.units).value);
1271
+ simulationTx.add(this_3.createTransferInstruction(sourceAta, destAta, fromPubkey, BigInt(amount.toFixed(0))));
940
1272
  return [2 /*return*/];
941
1273
  }
942
1274
  });
943
1275
  };
944
1276
  this_3 = this;
945
1277
  _i = 0, details_1 = details;
946
- _a.label = 2;
947
- case 2:
948
- if (!(_i < details_1.length)) return [3 /*break*/, 5];
1278
+ _a.label = 5;
1279
+ case 5:
1280
+ if (!(_i < details_1.length)) return [3 /*break*/, 8];
949
1281
  detail = details_1[_i];
950
1282
  return [5 /*yield**/, _loop_4(detail)];
951
- case 3:
952
- _a.sent();
953
- _a.label = 4;
954
- case 4:
955
- _i++;
956
- return [3 /*break*/, 2];
957
- case 5: return [3 /*break*/, 7];
958
1283
  case 6:
959
- e_8 = _a.sent();
960
- console.warn('[solana-spl][getTransactionFeeWithPublicKey] Failed to check ATA existence, assuming worst case');
961
- // Assume all destinations need ATA creation (worst case)
962
- totalAtaCreationCost = details.length * TOKEN_ACCOUNT_RENT_EXEMPTION_LAMPORTS;
963
- return [3 /*break*/, 7];
1284
+ _a.sent();
1285
+ _a.label = 7;
964
1286
  case 7:
965
- totalFee = baseFee + totalAtaCreationCost;
1287
+ _i++;
1288
+ return [3 /*break*/, 5];
1289
+ case 8: return [3 /*break*/, 10];
1290
+ case 9:
1291
+ e_11 = _a.sent();
1292
+ console.warn('[solana-spl][getTransactionFeeWithPublicKey] Failed to build simulation transaction:', e_11);
1293
+ ataCheckFailed = true;
1294
+ return [3 /*break*/, 10];
1295
+ case 10:
1296
+ simulationTx.feePayer = fromPubkey;
1297
+ baseFee = DEFAULT_BASE_FEE_LAMPORTS;
1298
+ _a.label = 11;
1299
+ case 11:
1300
+ _a.trys.push([11, 13, , 14]);
1301
+ return [4 /*yield*/, this.withFallback(function (connection) { return __awaiter(_this, void 0, void 0, function () {
1302
+ var blockhash, feeForMessage;
1303
+ return __generator(this, function (_a) {
1304
+ switch (_a.label) {
1305
+ case 0: return [4 /*yield*/, connection.getLatestBlockhash()];
1306
+ case 1:
1307
+ blockhash = (_a.sent()).blockhash;
1308
+ simulationTx.recentBlockhash = blockhash;
1309
+ return [4 /*yield*/, connection.getFeeForMessage(simulationTx.compileMessage())];
1310
+ case 2:
1311
+ feeForMessage = _a.sent();
1312
+ return [2 /*return*/, feeForMessage === null || feeForMessage === void 0 ? void 0 : feeForMessage.value];
1313
+ }
1314
+ });
1315
+ }); })];
1316
+ case 12:
1317
+ feeResult = _a.sent();
1318
+ if (feeResult && feeResult > 0) {
1319
+ baseFee = feeResult;
1320
+ }
1321
+ return [3 /*break*/, 14];
1322
+ case 13:
1323
+ e_12 = _a.sent();
1324
+ console.warn('[solana-spl][getTransactionFeeWithPublicKey] Failed to get base fee:', e_12);
1325
+ return [3 /*break*/, 14];
1326
+ case 14:
1327
+ computeUnits = (details.length * DEFAULT_SPL_TRANSFER_CU) + (ataCreationCount * DEFAULT_ATA_CREATE_CU);
1328
+ _a.label = 15;
1329
+ case 15:
1330
+ _a.trys.push([15, 17, , 18]);
1331
+ return [4 /*yield*/, this.simulateTransaction(simulationTx)];
1332
+ case 16:
1333
+ simulation = _a.sent();
1334
+ if (simulation.success && simulation.unitsConsumed > 0) {
1335
+ computeUnits = simulation.unitsConsumed;
1336
+ // Add 10% buffer to simulated CU for safety
1337
+ computeUnits = Math.ceil(computeUnits * 1.1);
1338
+ }
1339
+ return [3 /*break*/, 18];
1340
+ case 17:
1341
+ e_13 = _a.sent();
1342
+ console.warn('[solana-spl][getTransactionFeeWithPublicKey] Simulation failed, using default CU:', e_13);
1343
+ return [3 /*break*/, 18];
1344
+ case 18: return [4 /*yield*/, this.getRecentPriorityFees()
1345
+ // Calculate total fees for each tier
1346
+ // If ATA check failed, use conservative estimates:
1347
+ // - low: assume ATA exists (optimistic, just base fee)
1348
+ // - medium/high: include potential ATA creation cost
1349
+ ];
1350
+ case 19:
1351
+ priorityFees = _a.sent();
1352
+ baseOnly = baseFee;
1353
+ baseWithAta = baseFee + totalAtaCreationCost;
1354
+ if (ataCheckFailed) {
1355
+ potentialAtaCost = details.length * rentExemption;
1356
+ lowFee = baseOnly;
1357
+ mediumFee = this.calculateTotalFee(baseOnly, priorityFees.medium, computeUnits);
1358
+ highFee = this.calculateTotalFee(baseOnly + potentialAtaCost, priorityFees.high, computeUnits);
1359
+ }
1360
+ else {
1361
+ // ATA status is known - calculate exact fees
1362
+ lowFee = baseWithAta;
1363
+ mediumFee = this.calculateTotalFee(baseWithAta, priorityFees.medium, computeUnits);
1364
+ highFee = this.calculateTotalFee(baseWithAta, priorityFees.high, computeUnits);
1365
+ }
966
1366
  return [2 /*return*/, {
967
- low: (0, module_kit_1.newAmount)(totalFee, 'Lamports'),
968
- medium: (0, module_kit_1.newAmount)(totalFee, 'Lamports'),
969
- high: (0, module_kit_1.newAmount)(totalFee, 'Lamports')
1367
+ low: (0, module_kit_1.newAmount)(lowFee, 'Lamports'),
1368
+ medium: (0, module_kit_1.newAmount)(mediumFee, 'Lamports'),
1369
+ high: (0, module_kit_1.newAmount)(highFee, 'Lamports')
970
1370
  }];
971
1371
  }
972
1372
  });
@@ -985,7 +1385,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
985
1385
  mintPubkey = new solanaWeb3.PublicKey(this.options.contractAddress);
986
1386
  transaction = new solanaWeb3.Transaction();
987
1387
  _loop_5 = function (detail) {
988
- var toPubkey, sourceAta, destAta, destAtaInfo, createAtaIx, amount, transferIx;
1388
+ var toPubkey, sourceAta, destAta, destAtaInfo, needsWalletHint, createAtaIx, memoIx, amount, transferIx;
989
1389
  return __generator(this, function (_b) {
990
1390
  switch (_b.label) {
991
1391
  case 0:
@@ -1009,13 +1409,21 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
1009
1409
  }); }); })];
1010
1410
  case 3:
1011
1411
  destAtaInfo = _b.sent();
1412
+ needsWalletHint = true;
1012
1413
  if (!destAtaInfo) {
1013
1414
  createAtaIx = this_4.createAssociatedTokenAccountInstruction(fromPubkey, // payer
1014
1415
  destAta, // ata
1015
- toPubkey, // owner
1416
+ toPubkey, // owner (wallet address)
1016
1417
  mintPubkey // mint
1017
1418
  );
1018
1419
  transaction.add(createAtaIx);
1420
+ needsWalletHint = false;
1421
+ }
1422
+ // If ATA already exists, add a memo instruction with the wallet address hint
1423
+ // This allows Vault to resolve the destination wallet address offline
1424
+ if (needsWalletHint) {
1425
+ memoIx = this_4.createMemoInstruction("".concat(WALLET_HINT_PREFIX).concat(detail.to));
1426
+ transaction.add(memoIx);
1019
1427
  }
1020
1428
  amount = new bignumber_1.BigNumber((0, module_kit_1.newAmount)(detail.amount).blockchain(this_4.units).value);
1021
1429
  transferIx = this_4.createTransferInstruction(sourceAta, destAta, fromPubkey, BigInt(amount.toFixed(0)));
@@ -1077,6 +1485,14 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
1077
1485
  data: Buffer.alloc(0)
1078
1486
  });
1079
1487
  };
1488
+ // Helper: Create Memo instruction for wallet address hints
1489
+ SolanaSPLTokenProtocolImpl.prototype.createMemoInstruction = function (memo) {
1490
+ return new solanaWeb3.TransactionInstruction({
1491
+ keys: [],
1492
+ programId: MEMO_PROGRAM_ID,
1493
+ data: Buffer.from(memo, 'utf-8')
1494
+ });
1495
+ };
1080
1496
  // Helper: Create SPL Token transfer instruction
1081
1497
  SolanaSPLTokenProtocolImpl.prototype.createTransferInstruction = function (source, destination, owner, amount) {
1082
1498
  var data = Buffer.alloc(9);
@@ -1116,6 +1532,7 @@ var SolanaSPLTokenProtocolImpl = /** @class */ (function () {
1116
1532
  SolanaSPLTokenProtocolImpl.FALLBACK_RPC_URLS = [
1117
1533
  'https://solana.drpc.org'
1118
1534
  ];
1535
+ SolanaSPLTokenProtocolImpl.PRIORITY_FEE_CACHE_TTL = 30000; // 30 seconds cache
1119
1536
  // Default number of transactions to fetch per page
1120
1537
  SolanaSPLTokenProtocolImpl.DEFAULT_TX_LIMIT = 10;
1121
1538
  return SolanaSPLTokenProtocolImpl;