@t402/wdk 2.4.0 → 2.6.0

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.
Files changed (61) hide show
  1. package/dist/cjs/adapters/index.d.ts +198 -1
  2. package/dist/cjs/adapters/index.js +255 -0
  3. package/dist/cjs/adapters/index.js.map +1 -1
  4. package/dist/cjs/adapters/svm-adapter.d.ts +146 -2
  5. package/dist/cjs/adapters/svm-adapter.js +255 -2
  6. package/dist/cjs/adapters/svm-adapter.js.map +1 -1
  7. package/dist/cjs/adapters/ton-adapter.d.ts +57 -2
  8. package/dist/cjs/adapters/ton-adapter.js +75 -2
  9. package/dist/cjs/adapters/ton-adapter.js.map +1 -1
  10. package/dist/cjs/adapters/tron-adapter.d.ts +57 -2
  11. package/dist/cjs/adapters/tron-adapter.js +101 -0
  12. package/dist/cjs/adapters/tron-adapter.js.map +1 -1
  13. package/dist/cjs/index-DnEI5M6d.d.ts +1798 -0
  14. package/dist/cjs/index.d.ts +702 -1118
  15. package/dist/cjs/index.js +3905 -246
  16. package/dist/cjs/index.js.map +1 -1
  17. package/dist/cjs/integrations/index.d.ts +9 -0
  18. package/dist/cjs/integrations/index.js +249 -0
  19. package/dist/cjs/integrations/index.js.map +1 -0
  20. package/dist/cjs/testing/index.d.ts +62 -0
  21. package/dist/cjs/testing/index.js +129 -0
  22. package/dist/cjs/testing/index.js.map +1 -0
  23. package/dist/cjs/types-BwK8Xgvg.d.ts +967 -0
  24. package/dist/esm/adapters/index.d.mts +198 -1
  25. package/dist/esm/adapters/index.mjs +14 -3
  26. package/dist/esm/adapters/svm-adapter.d.mts +146 -2
  27. package/dist/esm/adapters/svm-adapter.mjs +18 -3
  28. package/dist/esm/adapters/ton-adapter.d.mts +57 -2
  29. package/dist/esm/adapters/ton-adapter.mjs +8 -3
  30. package/dist/esm/adapters/tron-adapter.d.mts +57 -2
  31. package/dist/esm/adapters/tron-adapter.mjs +2 -1
  32. package/dist/esm/chunk-2KWVW77U.mjs +353 -0
  33. package/dist/esm/chunk-2KWVW77U.mjs.map +1 -0
  34. package/dist/esm/chunk-7CG77QAN.mjs +153 -0
  35. package/dist/esm/chunk-7CG77QAN.mjs.map +1 -0
  36. package/dist/esm/chunk-BJTO5JO5.mjs +11 -0
  37. package/dist/esm/chunk-BJTO5JO5.mjs.map +1 -0
  38. package/dist/esm/{chunk-YWBJJV5M.mjs → chunk-KWX6CJIH.mjs} +72 -1
  39. package/dist/esm/chunk-KWX6CJIH.mjs.map +1 -0
  40. package/dist/esm/{chunk-HB2DGKQ3.mjs → chunk-QZKUU2O6.mjs} +102 -1
  41. package/dist/esm/chunk-QZKUU2O6.mjs.map +1 -0
  42. package/dist/esm/chunk-TVSNUSFZ.mjs +219 -0
  43. package/dist/esm/chunk-TVSNUSFZ.mjs.map +1 -0
  44. package/dist/esm/index-D5kvtDfm.d.mts +1798 -0
  45. package/dist/esm/index.d.mts +702 -1118
  46. package/dist/esm/index.mjs +2934 -70
  47. package/dist/esm/index.mjs.map +1 -1
  48. package/dist/esm/integrations/index.d.mts +9 -0
  49. package/dist/esm/integrations/index.mjs +16 -0
  50. package/dist/esm/integrations/index.mjs.map +1 -0
  51. package/dist/esm/testing/index.d.mts +62 -0
  52. package/dist/esm/testing/index.mjs +101 -0
  53. package/dist/esm/testing/index.mjs.map +1 -0
  54. package/dist/esm/types-BwK8Xgvg.d.mts +967 -0
  55. package/package.json +69 -20
  56. package/dist/cjs/types-V7c-qhn6.d.ts +0 -489
  57. package/dist/esm/chunk-HB2DGKQ3.mjs.map +0 -1
  58. package/dist/esm/chunk-MCFHZSF7.mjs +0 -107
  59. package/dist/esm/chunk-MCFHZSF7.mjs.map +0 -1
  60. package/dist/esm/chunk-YWBJJV5M.mjs.map +0 -1
  61. package/dist/esm/types-V7c-qhn6.d.mts +0 -489
package/dist/cjs/index.js CHANGED
@@ -30,24 +30,36 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AmountLimitProvider: () => AmountLimitProvider,
33
34
  BalanceCache: () => BalanceCache,
34
35
  BalanceError: () => BalanceError,
36
+ BlacklistProvider: () => BlacklistProvider,
35
37
  BridgeError: () => BridgeError,
38
+ BridgeTracker: () => BridgeTracker,
39
+ CHAIN_REGISTRY: () => CHAIN_REGISTRY,
36
40
  CHAIN_TOKENS: () => CHAIN_TOKENS,
37
41
  ChainError: () => ChainError,
42
+ ComplianceManager: () => ComplianceManager,
38
43
  DEFAULT_BALANCE_CACHE_CONFIG: () => DEFAULT_BALANCE_CACHE_CONFIG,
39
44
  DEFAULT_CACHE_CONFIG: () => DEFAULT_CACHE_CONFIG,
40
45
  DEFAULT_CHAINS: () => DEFAULT_CHAINS,
41
46
  DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
42
47
  DEFAULT_RPC_ENDPOINTS: () => DEFAULT_RPC_ENDPOINTS,
48
+ FailoverProvider: () => FailoverProvider,
43
49
  HardwareWalletError: () => HardwareWalletError,
44
50
  HardwareWalletErrorCode: () => HardwareWalletErrorCode,
51
+ InMemoryIdempotencyManager: () => InMemoryIdempotencyManager,
52
+ InMemoryReceiptStore: () => InMemoryReceiptStore,
45
53
  LAYERZERO_ENDPOINT_IDS: () => import_evm3.LAYERZERO_ENDPOINT_IDS,
46
54
  LedgerSigner: () => LedgerSigner,
47
55
  MockWDKSigner: () => MockWDKSigner,
56
+ MoonpayOnRampProvider: () => MoonpayOnRampProvider,
57
+ NonceManager: () => NonceManager,
48
58
  RPCError: () => RPCError,
59
+ SUPPORTED_WDK_RANGE: () => SUPPORTED_WDK_RANGE,
49
60
  SignerError: () => SignerError,
50
61
  SigningError: () => SigningError,
62
+ T402EventEmitter: () => T402EventEmitter,
51
63
  T402WDK: () => T402WDK,
52
64
  TTLCache: () => TTLCache,
53
65
  TransactionError: () => TransactionError,
@@ -66,34 +78,336 @@ __export(index_exports, {
66
78
  WDKTronSignerAdapter: () => WDKTronSignerAdapter,
67
79
  WDK_COMPATIBILITY: () => WDK_COMPATIBILITY,
68
80
  WdkBridge: () => WdkBridge,
81
+ WdkIndexerVerifier: () => WdkIndexerVerifier,
82
+ WebhookManager: () => WebhookManager,
83
+ buildVersionedTransaction: () => buildVersionedTransaction,
69
84
  checkWalletEvmCompatibility: () => checkWalletEvmCompatibility,
70
85
  checkWdkCompatibility: () => checkWdkCompatibility,
86
+ compareSemver: () => compareSemver,
87
+ createBackup: () => createBackup,
88
+ createCorrelationId: () => createCorrelationId,
71
89
  createDirectBridge: () => createDirectBridge,
90
+ createFacilitatorSigners: () => createFacilitatorSigners,
91
+ createFailoverProvider: () => createFailoverProvider,
92
+ createIndexerVerifier: () => createIndexerVerifier,
72
93
  createLedgerSigner: () => createLedgerSigner,
94
+ createSIWxSigners: () => createSIWxSigners,
73
95
  createTrezorSigner: () => createTrezorSigner,
74
96
  createWDKSigner: () => createWDKSigner,
75
97
  createWDKSvmSigner: () => createWDKSvmSigner,
76
98
  createWDKTonSigner: () => createWDKTonSigner,
77
99
  createWDKTronSigner: () => createWDKTronSigner,
100
+ createWdkA2APaymentClient: () => createWdkA2APaymentClient,
101
+ createWdkMoneyParser: () => createWdkMoneyParser,
102
+ decryptSeed: () => decryptSeed,
103
+ defaultLogger: () => defaultLogger,
104
+ deriveATAAddress: () => deriveATAAddress,
78
105
  detectHardwareWalletSupport: () => detectHardwareWalletSupport,
106
+ encryptSeed: () => encryptSeed,
107
+ generateIdempotencyKey: () => generateIdempotencyKey,
79
108
  getBridgeableChains: () => import_evm3.getBridgeableChains,
80
109
  getChainFromNetwork: () => getChainFromNetwork,
81
110
  getChainId: () => getChainId,
111
+ getChainsByFamily: () => getChainsByFamily,
112
+ getJettonWalletAddress: () => getJettonWalletAddress,
113
+ getMoonpayCurrencyCode: () => getMoonpayCurrencyCode,
82
114
  getNetworkFromChain: () => getNetworkFromChain,
83
115
  getPreferredToken: () => getPreferredToken,
116
+ getPricingProvider: () => getPricingProvider,
117
+ getRecentPriorityFees: () => getRecentPriorityFees,
118
+ getRegistryByCaip2: () => getRegistryByCaip2,
119
+ getSecretManager: () => getSecretManager,
120
+ getTokenProgram: () => getTokenProgram,
121
+ getTransferFee: () => getTransferFee,
84
122
  getUsdt0Chains: () => getUsdt0Chains,
85
123
  getWalletModuleMinVersion: () => getWalletModuleMinVersion,
86
124
  hasErrorCode: () => hasErrorCode,
87
125
  isHardwareWalletSupported: () => isHardwareWalletSupported,
126
+ isPricingProviderRegistered: () => isPricingProviderRegistered,
88
127
  isWDKError: () => isWDKError,
128
+ mapLayerZeroStatus: () => mapLayerZeroStatus,
129
+ noopLogger: () => noopLogger,
89
130
  normalizeChainConfig: () => normalizeChainConfig,
131
+ parseSemver: () => parseSemver,
132
+ registerPricingProvider: () => registerPricingProvider,
133
+ registerSecretManager: () => registerSecretManager,
134
+ resolveATA: () => resolveATA,
135
+ resolveAssetForNetwork: () => resolveAssetForNetwork,
136
+ resolveRpcUrl: () => resolveRpcUrl,
137
+ rotateSeedPassword: () => rotateSeedPassword,
138
+ satisfiesSemverRange: () => satisfiesSemverRange,
90
139
  supportsBridging: () => import_evm3.supportsBridging,
140
+ toAtomicUnits: () => toAtomicUnits,
141
+ toFacilitatorWdkSigner: () => toFacilitatorWdkSigner,
142
+ toSIWxSigner: () => toSIWxSigner,
143
+ transferWithPriorityFee: () => transferWithPriorityFee,
144
+ validatePaymentAddress: () => validatePaymentAddress,
145
+ verifyBackup: () => verifyBackup,
146
+ waitForJettonTransfer: () => waitForJettonTransfer,
91
147
  withRetry: () => withRetry,
92
148
  withTimeout: () => withTimeout,
93
149
  wrapError: () => wrapError
94
150
  });
95
151
  module.exports = __toCommonJS(index_exports);
96
152
 
153
+ // src/secret.ts
154
+ var _secretManager = null;
155
+ async function encryptSeed(seedPhrase, password) {
156
+ if (!seedPhrase || typeof seedPhrase !== "string") {
157
+ throw new Error("Seed phrase is required and must be a string");
158
+ }
159
+ if (!password || typeof password !== "string") {
160
+ throw new Error("Password is required and must be a string");
161
+ }
162
+ const crypto = await import("crypto");
163
+ const salt = crypto.randomBytes(32);
164
+ const iv = crypto.randomBytes(16);
165
+ const key = crypto.pbkdf2Sync(password, salt, 1e5, 32, "sha256");
166
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
167
+ const encrypted = Buffer.concat([cipher.update(seedPhrase, "utf8"), cipher.final()]);
168
+ const authTag = cipher.getAuthTag();
169
+ return {
170
+ ciphertext: Buffer.concat([encrypted, authTag]).toString("base64"),
171
+ algorithm: "aes-256-gcm",
172
+ kdf: {
173
+ salt: salt.toString("base64"),
174
+ iterations: 1e5,
175
+ keyLength: 32,
176
+ hash: "sha256"
177
+ },
178
+ iv: iv.toString("base64"),
179
+ version: 1
180
+ };
181
+ }
182
+ async function decryptSeed(encrypted, password) {
183
+ if (!encrypted || typeof encrypted !== "object") {
184
+ throw new Error("Encrypted seed data is required");
185
+ }
186
+ if (!password || typeof password !== "string") {
187
+ throw new Error("Password is required and must be a string");
188
+ }
189
+ const crypto = await import("crypto");
190
+ const salt = Buffer.from(encrypted.kdf.salt, "base64");
191
+ const iv = Buffer.from(encrypted.iv, "base64");
192
+ const key = crypto.pbkdf2Sync(
193
+ password,
194
+ salt,
195
+ encrypted.kdf.iterations,
196
+ encrypted.kdf.keyLength,
197
+ encrypted.kdf.hash
198
+ );
199
+ const data = Buffer.from(encrypted.ciphertext, "base64");
200
+ const authTag = data.subarray(-16);
201
+ const ciphertext = data.subarray(0, -16);
202
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
203
+ decipher.setAuthTag(authTag);
204
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
205
+ }
206
+ async function rotateSeedPassword(encrypted, oldPassword, newPassword, options) {
207
+ if (!newPassword || typeof newPassword !== "string") {
208
+ throw new Error("New password is required and must be a string");
209
+ }
210
+ const manager = getSecretManager();
211
+ const seedPhrase = await manager.decrypt(encrypted, oldPassword);
212
+ const iterations = options?.iterations ?? encrypted.kdf.iterations;
213
+ const newVersion = options?.iterations && options.iterations !== encrypted.kdf.iterations ? 2 : encrypted.version;
214
+ const crypto = await import("crypto");
215
+ const salt = crypto.randomBytes(32);
216
+ const iv = crypto.randomBytes(16);
217
+ const key = crypto.pbkdf2Sync(newPassword, salt, iterations, 32, "sha256");
218
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
219
+ const encryptedData = Buffer.concat([cipher.update(seedPhrase, "utf8"), cipher.final()]);
220
+ const authTag = cipher.getAuthTag();
221
+ return {
222
+ ciphertext: Buffer.concat([encryptedData, authTag]).toString("base64"),
223
+ algorithm: "aes-256-gcm",
224
+ kdf: {
225
+ salt: salt.toString("base64"),
226
+ iterations,
227
+ keyLength: 32,
228
+ hash: "sha256"
229
+ },
230
+ iv: iv.toString("base64"),
231
+ version: newVersion
232
+ };
233
+ }
234
+ function registerSecretManager(manager) {
235
+ _secretManager = manager;
236
+ }
237
+ function getSecretManager() {
238
+ if (_secretManager) {
239
+ return _secretManager;
240
+ }
241
+ return {
242
+ encrypt: encryptSeed,
243
+ decrypt: decryptSeed
244
+ };
245
+ }
246
+ async function createBackup(seedPhrase, password, metadata) {
247
+ if (!seedPhrase || typeof seedPhrase !== "string") {
248
+ throw new Error("Seed phrase is required and must be a string");
249
+ }
250
+ if (!password || typeof password !== "string") {
251
+ throw new Error("Password is required and must be a string");
252
+ }
253
+ const manager = getSecretManager();
254
+ const encrypted = await manager.encrypt(seedPhrase, password);
255
+ const envelope = {
256
+ encrypted,
257
+ metadata
258
+ };
259
+ return JSON.stringify(envelope, null, 2);
260
+ }
261
+ async function verifyBackup(backup, password, expectedAddresses) {
262
+ let envelope;
263
+ try {
264
+ envelope = JSON.parse(backup);
265
+ } catch {
266
+ return { valid: false, addressMatch: false };
267
+ }
268
+ if (!envelope.encrypted || !envelope.metadata) {
269
+ return { valid: false, addressMatch: false };
270
+ }
271
+ try {
272
+ const manager = getSecretManager();
273
+ await manager.decrypt(envelope.encrypted, password);
274
+ } catch {
275
+ return { valid: false, addressMatch: false };
276
+ }
277
+ let addressMatch = true;
278
+ if (expectedAddresses && envelope.metadata.addressHints) {
279
+ for (const [chain, expectedAddr] of Object.entries(expectedAddresses)) {
280
+ const hint = envelope.metadata.addressHints[chain];
281
+ if (hint && hint.toLowerCase() !== expectedAddr.toLowerCase()) {
282
+ addressMatch = false;
283
+ break;
284
+ }
285
+ }
286
+ }
287
+ return { valid: true, addressMatch, metadata: envelope.metadata };
288
+ }
289
+
290
+ // src/events.ts
291
+ var T402EventEmitter = class {
292
+ handlers = /* @__PURE__ */ new Map();
293
+ on(event, handler) {
294
+ let set = this.handlers.get(event);
295
+ if (!set) {
296
+ set = /* @__PURE__ */ new Set();
297
+ this.handlers.set(event, set);
298
+ }
299
+ set.add(handler);
300
+ return this;
301
+ }
302
+ off(event, handler) {
303
+ const set = this.handlers.get(event);
304
+ if (set) {
305
+ set.delete(handler);
306
+ if (set.size === 0) {
307
+ this.handlers.delete(event);
308
+ }
309
+ }
310
+ return this;
311
+ }
312
+ once(event, handler) {
313
+ const wrapper = (data) => {
314
+ this.off(event, wrapper);
315
+ handler(data);
316
+ };
317
+ return this.on(event, wrapper);
318
+ }
319
+ emit(event, data) {
320
+ const set = this.handlers.get(event);
321
+ if (!set || set.size === 0) {
322
+ return false;
323
+ }
324
+ for (const handler of set) {
325
+ handler(data);
326
+ }
327
+ return true;
328
+ }
329
+ removeAllListeners(event) {
330
+ if (event) {
331
+ this.handlers.delete(event);
332
+ } else {
333
+ this.handlers.clear();
334
+ }
335
+ return this;
336
+ }
337
+ listenerCount(event) {
338
+ return this.handlers.get(event)?.size ?? 0;
339
+ }
340
+ };
341
+
342
+ // src/receipts.ts
343
+ var InMemoryReceiptStore = class {
344
+ receipts = /* @__PURE__ */ new Map();
345
+ async save(receipt) {
346
+ this.receipts.set(receipt.id, receipt);
347
+ }
348
+ async getById(id) {
349
+ return this.receipts.get(id) ?? null;
350
+ }
351
+ async query(filter) {
352
+ let results = Array.from(this.receipts.values());
353
+ results = applyFilter(results, filter);
354
+ return results;
355
+ }
356
+ async getAll() {
357
+ return Array.from(this.receipts.values());
358
+ }
359
+ async count(filter) {
360
+ if (!filter) {
361
+ return this.receipts.size;
362
+ }
363
+ const filtered = applyFilter(Array.from(this.receipts.values()), filter);
364
+ return filtered.length;
365
+ }
366
+ async clear() {
367
+ this.receipts.clear();
368
+ }
369
+ async exportJSON() {
370
+ return JSON.stringify(Array.from(this.receipts.values()), null, 2);
371
+ }
372
+ };
373
+ function applyFilter(receipts, filter) {
374
+ if (!filter) return receipts;
375
+ let results = receipts;
376
+ if (filter.network !== void 0) {
377
+ results = results.filter((r) => r.network === filter.network);
378
+ }
379
+ if (filter.chainFamily !== void 0) {
380
+ results = results.filter((r) => r.chainFamily === filter.chainFamily);
381
+ }
382
+ if (filter.success !== void 0) {
383
+ results = results.filter((r) => r.success === filter.success);
384
+ }
385
+ if (filter.fromDate !== void 0) {
386
+ const from = filter.fromDate;
387
+ results = results.filter((r) => r.timestamp >= from);
388
+ }
389
+ if (filter.toDate !== void 0) {
390
+ const to = filter.toDate;
391
+ results = results.filter((r) => r.timestamp <= to);
392
+ }
393
+ if (filter.minAmount !== void 0) {
394
+ const min = BigInt(filter.minAmount);
395
+ results = results.filter((r) => BigInt(r.amount) >= min);
396
+ }
397
+ if (filter.maxAmount !== void 0) {
398
+ const max = BigInt(filter.maxAmount);
399
+ results = results.filter((r) => BigInt(r.amount) <= max);
400
+ }
401
+ results.sort((a, b) => a.timestamp > b.timestamp ? -1 : a.timestamp < b.timestamp ? 1 : 0);
402
+ if (filter.offset !== void 0 && filter.offset > 0) {
403
+ results = results.slice(filter.offset);
404
+ }
405
+ if (filter.limit !== void 0 && filter.limit > 0) {
406
+ results = results.slice(0, filter.limit);
407
+ }
408
+ return results;
409
+ }
410
+
97
411
  // src/adapters/ton-adapter.ts
98
412
  var WDKTonAddress = class {
99
413
  constructor(_address) {
@@ -200,6 +514,75 @@ var WDKTonSignerAdapter = class {
200
514
  return this._account;
201
515
  }
202
516
  };
517
+ async function waitForJettonTransfer(apiEndpoint, params) {
518
+ const timeout = params.timeoutMs ?? 12e4;
519
+ const pollInterval = params.pollIntervalMs ?? 3e3;
520
+ const startTime = Date.now();
521
+ params.onStatusChange?.("pending");
522
+ while (Date.now() - startTime < timeout) {
523
+ try {
524
+ const response = await fetch(
525
+ `${apiEndpoint}/getTransactions?hash=${encodeURIComponent(params.externalMessageHash)}&limit=1`
526
+ );
527
+ if (!response.ok) {
528
+ await new Promise((r) => setTimeout(r, pollInterval));
529
+ continue;
530
+ }
531
+ const data = await response.json();
532
+ if (data.ok && data.result && data.result.length > 0) {
533
+ const tx = data.result[0];
534
+ if (tx.out_msgs && tx.out_msgs.length > 0) {
535
+ params.onStatusChange?.("confirming");
536
+ const txHash = tx.transaction_id?.hash ?? params.externalMessageHash;
537
+ await new Promise((r) => setTimeout(r, pollInterval));
538
+ params.onStatusChange?.("completed");
539
+ return {
540
+ success: true,
541
+ status: "completed",
542
+ transactionHash: txHash
543
+ };
544
+ }
545
+ }
546
+ } catch {
547
+ }
548
+ await new Promise((r) => setTimeout(r, pollInterval));
549
+ }
550
+ params.onStatusChange?.("timeout");
551
+ return {
552
+ success: false,
553
+ status: "timeout",
554
+ error: `Jetton transfer not confirmed within ${timeout}ms`
555
+ };
556
+ }
557
+ async function getJettonWalletAddress(apiEndpoint, ownerAddress, jettonMaster) {
558
+ const response = await fetch(`${apiEndpoint}/runGetMethod`, {
559
+ method: "POST",
560
+ headers: { "Content-Type": "application/json" },
561
+ body: JSON.stringify({
562
+ address: jettonMaster,
563
+ method: "get_wallet_address",
564
+ stack: [["tvm.Slice", ownerAddress]]
565
+ })
566
+ });
567
+ if (!response.ok) {
568
+ throw new Error(`Failed to resolve Jetton wallet address: ${response.status}`);
569
+ }
570
+ const result = await response.json();
571
+ if (!result.ok || !result.result) {
572
+ throw new Error("Failed to resolve Jetton wallet address: invalid response");
573
+ }
574
+ if (result.result.exit_code !== void 0 && result.result.exit_code !== 0) {
575
+ throw new Error(`Jetton master GET method failed with exit code ${result.result.exit_code}`);
576
+ }
577
+ if (!result.result.stack || result.result.stack.length === 0) {
578
+ throw new Error("Failed to resolve Jetton wallet address: empty stack");
579
+ }
580
+ const walletAddress = result.result.stack[0]?.[1];
581
+ if (!walletAddress) {
582
+ throw new Error("Failed to parse Jetton wallet address from response");
583
+ }
584
+ return walletAddress;
585
+ }
203
586
  async function createWDKTonSigner(account) {
204
587
  const adapter = new WDKTonSignerAdapter(account);
205
588
  await adapter.initialize();
@@ -302,6 +685,245 @@ var WDKSvmSignerAdapter = class {
302
685
  return this._account.transfer(params);
303
686
  }
304
687
  };
688
+ var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
689
+ var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
690
+ var TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
691
+ var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
692
+ function buildVersionedTransaction(adapter, params) {
693
+ if (!adapter.isInitialized) {
694
+ throw new Error("Adapter must be initialized before building transactions");
695
+ }
696
+ const allInstructions = [];
697
+ if (params.priorityFee) {
698
+ allInstructions.push(
699
+ createSetComputeUnitLimitInstruction(params.priorityFee.computeUnits ?? 2e5)
700
+ );
701
+ allInstructions.push(createSetComputeUnitPriceInstruction(params.priorityFee.microLamports));
702
+ }
703
+ allInstructions.push(...params.instructions);
704
+ const lookupTableCount = params.addressLookupTableAccounts?.length ?? 0;
705
+ const header = {
706
+ version: 0,
707
+ numSigners: 1,
708
+ numReadonlySignedAccounts: 0,
709
+ numReadonlyUnsignedAccounts: 0,
710
+ feePayer: adapter.address,
711
+ instructions: allInstructions,
712
+ lookupTableCount
713
+ };
714
+ return serializeVersionedMessage(header);
715
+ }
716
+ async function transferWithPriorityFee(adapter, params) {
717
+ if (!adapter.isInitialized) {
718
+ throw new Error("Adapter must be initialized before transferring");
719
+ }
720
+ return adapter.transfer({
721
+ token: params.token,
722
+ recipient: params.recipient,
723
+ amount: params.amount
724
+ });
725
+ }
726
+ async function getRecentPriorityFees(rpcUrl) {
727
+ const response = await fetch(rpcUrl, {
728
+ method: "POST",
729
+ headers: { "Content-Type": "application/json" },
730
+ body: JSON.stringify({
731
+ jsonrpc: "2.0",
732
+ id: 1,
733
+ method: "getRecentPrioritizationFees",
734
+ params: []
735
+ })
736
+ });
737
+ if (!response.ok) {
738
+ throw new Error(`RPC request failed: ${response.status}`);
739
+ }
740
+ const result = await response.json();
741
+ if (result.error) {
742
+ throw new Error(`RPC error: ${result.error.message}`);
743
+ }
744
+ const fees = result.result ?? [];
745
+ if (fees.length === 0) {
746
+ return { low: 0, medium: 0, high: 0 };
747
+ }
748
+ const sorted = fees.map((f) => f.prioritizationFee).sort((a, b) => a - b);
749
+ const p25 = sorted[Math.floor(sorted.length * 0.25)] ?? 0;
750
+ const p50 = sorted[Math.floor(sorted.length * 0.5)] ?? 0;
751
+ const p75 = sorted[Math.floor(sorted.length * 0.75)] ?? 0;
752
+ return { low: p25, medium: p50, high: p75 };
753
+ }
754
+ async function resolveATA(rpcUrl, owner, mint) {
755
+ const ataAddress = deriveATAAddress(owner, mint);
756
+ const response = await fetch(rpcUrl, {
757
+ method: "POST",
758
+ headers: { "Content-Type": "application/json" },
759
+ body: JSON.stringify({
760
+ jsonrpc: "2.0",
761
+ id: 1,
762
+ method: "getAccountInfo",
763
+ params: [ataAddress, { encoding: "base64" }]
764
+ })
765
+ });
766
+ if (!response.ok) {
767
+ throw new Error(`RPC request failed: ${response.status}`);
768
+ }
769
+ const result = await response.json();
770
+ if (result.error) {
771
+ throw new Error(`RPC error: ${result.error.message}`);
772
+ }
773
+ const exists = result.result?.value != null;
774
+ if (exists) {
775
+ return { address: ataAddress, exists: true };
776
+ }
777
+ return {
778
+ address: ataAddress,
779
+ exists: false,
780
+ createInstruction: {
781
+ programId: ASSOCIATED_TOKEN_PROGRAM_ID,
782
+ keys: [
783
+ { pubkey: owner, isSigner: true, isWritable: true },
784
+ { pubkey: ataAddress, isSigner: false, isWritable: true },
785
+ { pubkey: owner, isSigner: false, isWritable: false },
786
+ { pubkey: mint, isSigner: false, isWritable: false },
787
+ { pubkey: "11111111111111111111111111111111", isSigner: false, isWritable: false },
788
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
789
+ ],
790
+ data: new Uint8Array(0)
791
+ }
792
+ };
793
+ }
794
+ async function getTokenProgram(rpcUrl, mint) {
795
+ const response = await fetch(rpcUrl, {
796
+ method: "POST",
797
+ headers: { "Content-Type": "application/json" },
798
+ body: JSON.stringify({
799
+ jsonrpc: "2.0",
800
+ id: 1,
801
+ method: "getAccountInfo",
802
+ params: [mint, { encoding: "jsonParsed" }]
803
+ })
804
+ });
805
+ if (!response.ok) {
806
+ throw new Error(`RPC request failed: ${response.status}`);
807
+ }
808
+ const result = await response.json();
809
+ if (result.error) {
810
+ throw new Error(`RPC error: ${result.error.message}`);
811
+ }
812
+ if (!result.result?.value) {
813
+ throw new Error(`Mint account not found: ${mint}`);
814
+ }
815
+ const owner = result.result.value.owner;
816
+ if (owner === TOKEN_2022_PROGRAM_ID) {
817
+ return "Token-2022";
818
+ }
819
+ return "Token";
820
+ }
821
+ async function getTransferFee(rpcUrl, mint, amount) {
822
+ const response = await fetch(rpcUrl, {
823
+ method: "POST",
824
+ headers: { "Content-Type": "application/json" },
825
+ body: JSON.stringify({
826
+ jsonrpc: "2.0",
827
+ id: 1,
828
+ method: "getAccountInfo",
829
+ params: [mint, { encoding: "jsonParsed" }]
830
+ })
831
+ });
832
+ if (!response.ok) {
833
+ throw new Error(`RPC request failed: ${response.status}`);
834
+ }
835
+ const result = await response.json();
836
+ if (result.error) {
837
+ throw new Error(`RPC error: ${result.error.message}`);
838
+ }
839
+ if (!result.result?.value) {
840
+ throw new Error(`Mint account not found: ${mint}`);
841
+ }
842
+ const extensions = result.result.value.data?.parsed?.info?.extensions ?? [];
843
+ const transferFeeExt = extensions.find((e) => e.extension === "transferFeeConfig");
844
+ if (!transferFeeExt?.state) {
845
+ return { fee: 0n, netAmount: amount, transferFeeBasisPoints: 0, maximumFee: 0n };
846
+ }
847
+ const feeConfig = transferFeeExt.state.newerTransferFee ?? transferFeeExt.state.olderTransferFee;
848
+ if (!feeConfig) {
849
+ return { fee: 0n, netAmount: amount, transferFeeBasisPoints: 0, maximumFee: 0n };
850
+ }
851
+ const basisPoints = feeConfig.transferFeeBasisPoints;
852
+ const maxFee = BigInt(feeConfig.maximumFee);
853
+ let fee = amount * BigInt(basisPoints) / 10000n;
854
+ if (fee > maxFee) fee = maxFee;
855
+ return {
856
+ fee,
857
+ netAmount: amount - fee,
858
+ transferFeeBasisPoints: basisPoints,
859
+ maximumFee: maxFee
860
+ };
861
+ }
862
+ function createSetComputeUnitLimitInstruction(units) {
863
+ const data = new Uint8Array(5);
864
+ data[0] = 2;
865
+ const view = new DataView(data.buffer);
866
+ view.setUint32(1, units, true);
867
+ return {
868
+ programId: COMPUTE_BUDGET_PROGRAM_ID,
869
+ keys: [],
870
+ data
871
+ };
872
+ }
873
+ function createSetComputeUnitPriceInstruction(microLamports) {
874
+ const data = new Uint8Array(9);
875
+ data[0] = 3;
876
+ const view = new DataView(data.buffer);
877
+ view.setUint32(1, microLamports & 4294967295, true);
878
+ view.setUint32(5, Math.floor(microLamports / 4294967296) & 4294967295, true);
879
+ return {
880
+ programId: COMPUTE_BUDGET_PROGRAM_ID,
881
+ keys: [],
882
+ data
883
+ };
884
+ }
885
+ function deriveATAAddress(owner, mint) {
886
+ return `ata:${owner}:${mint}`;
887
+ }
888
+ function serializeVersionedMessage(header) {
889
+ const encoder = new TextEncoder();
890
+ const parts = [];
891
+ parts.push(new Uint8Array([128]));
892
+ parts.push(
893
+ new Uint8Array([
894
+ header.numSigners,
895
+ header.numReadonlySignedAccounts,
896
+ header.numReadonlyUnsignedAccounts
897
+ ])
898
+ );
899
+ const feePayerBytes = encoder.encode(header.feePayer);
900
+ parts.push(new Uint8Array([feePayerBytes.length]));
901
+ parts.push(feePayerBytes);
902
+ parts.push(new Uint8Array([header.instructions.length]));
903
+ for (const ix of header.instructions) {
904
+ const pidBytes = encoder.encode(ix.programId);
905
+ parts.push(new Uint8Array([pidBytes.length]));
906
+ parts.push(pidBytes);
907
+ parts.push(new Uint8Array([ix.keys.length]));
908
+ for (const key of ix.keys) {
909
+ const keyBytes = encoder.encode(key.pubkey);
910
+ parts.push(new Uint8Array([keyBytes.length]));
911
+ parts.push(keyBytes);
912
+ parts.push(new Uint8Array([key.isSigner ? 1 : 0, key.isWritable ? 1 : 0]));
913
+ }
914
+ parts.push(new Uint8Array([ix.data.length]));
915
+ parts.push(ix.data);
916
+ }
917
+ parts.push(new Uint8Array([header.lookupTableCount]));
918
+ const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
919
+ const result = new Uint8Array(totalLength);
920
+ let offset = 0;
921
+ for (const part of parts) {
922
+ result.set(part, offset);
923
+ offset += part.length;
924
+ }
925
+ return result;
926
+ }
305
927
  async function createWDKSvmSigner(account) {
306
928
  const adapter = new WDKSvmSignerAdapter(account);
307
929
  await adapter.initialize();
@@ -314,6 +936,7 @@ var WDKTronSignerAdapter = class {
314
936
  _address = null;
315
937
  _initialized = false;
316
938
  _rpcUrl;
939
+ _energyProvider = null;
317
940
  constructor(account, rpcUrl = "https://api.trongrid.io") {
318
941
  if (!account) {
319
942
  throw new Error("WDK TRON account is required");
@@ -415,6 +1038,106 @@ var WDKTronSignerAdapter = class {
415
1038
  );
416
1039
  }
417
1040
  }
1041
+ /**
1042
+ * Estimate the energy required for a TRC20 transfer.
1043
+ *
1044
+ * Uses the `wallet/triggerconstantcontract` API to simulate the transfer
1045
+ * and return the energy/bandwidth requirements.
1046
+ *
1047
+ * @param params - Transaction parameters to simulate
1048
+ * @returns Energy estimation result
1049
+ */
1050
+ async estimateEnergy(params) {
1051
+ if (!this._address) {
1052
+ throw new Error("TRON signer not initialized. Call initialize() first.");
1053
+ }
1054
+ const functionSelector = "transfer(address,uint256)";
1055
+ const toAddressHex = this.addressToHex(params.to).slice(2).padStart(64, "0");
1056
+ const amountHex = BigInt(params.amount).toString(16).padStart(64, "0");
1057
+ const parameter = toAddressHex + amountHex;
1058
+ try {
1059
+ const response = await fetch(`${this._rpcUrl}/wallet/triggerconstantcontract`, {
1060
+ method: "POST",
1061
+ headers: { "Content-Type": "application/json" },
1062
+ body: JSON.stringify({
1063
+ owner_address: this.addressToHex(this._address),
1064
+ contract_address: this.addressToHex(params.contractAddress),
1065
+ function_selector: functionSelector,
1066
+ parameter
1067
+ })
1068
+ });
1069
+ if (!response.ok) {
1070
+ throw new Error(`Energy estimation failed: ${response.status}`);
1071
+ }
1072
+ const result = await response.json();
1073
+ if (result.result?.code && result.result.code !== "SUCCESS") {
1074
+ throw new Error(`Energy estimation failed: ${result.result.message ?? result.result.code}`);
1075
+ }
1076
+ const energyRequired = (result.energy_used ?? 0) + (result.energy_penalty ?? 0);
1077
+ const resourceResponse = await fetch(`${this._rpcUrl}/wallet/getaccountresource`, {
1078
+ method: "POST",
1079
+ headers: { "Content-Type": "application/json" },
1080
+ body: JSON.stringify({
1081
+ address: this.addressToHex(this._address)
1082
+ })
1083
+ });
1084
+ let energyAvailable = 0;
1085
+ if (resourceResponse.ok) {
1086
+ const resources = await resourceResponse.json();
1087
+ energyAvailable = (resources.EnergyLimit ?? 0) - (resources.EnergyUsed ?? 0);
1088
+ }
1089
+ const bandwidthRequired = 350;
1090
+ const trxCostIfNoEnergy = BigInt(Math.max(0, energyRequired - energyAvailable)) * 420n;
1091
+ return {
1092
+ energyRequired,
1093
+ energyAvailable,
1094
+ trxCostIfNoEnergy,
1095
+ bandwidthRequired
1096
+ };
1097
+ } catch (error) {
1098
+ throw new Error(
1099
+ `Failed to estimate energy: ${error instanceof Error ? error.message : String(error)}`
1100
+ );
1101
+ }
1102
+ }
1103
+ /**
1104
+ * Sign a TRC20 transfer with dynamic fee limit estimation.
1105
+ *
1106
+ * Instead of using a hardcoded 100 TRX fee limit, estimates the actual
1107
+ * energy cost and adds a 20% margin.
1108
+ *
1109
+ * @param params - Transaction parameters
1110
+ * @returns Hex-encoded signed transaction
1111
+ */
1112
+ async signTransactionWithEstimation(params) {
1113
+ if (!params.feeLimit) {
1114
+ const estimate = await this.estimateEnergy(params);
1115
+ const estimatedFee = estimate.trxCostIfNoEnergy;
1116
+ const feeWithMargin = estimatedFee + estimatedFee * 20n / 100n;
1117
+ const feeLimitSun = Number(
1118
+ feeWithMargin < 10000000n ? 10000000n : feeWithMargin > 150000000n ? 150000000n : feeWithMargin
1119
+ );
1120
+ return this.signTransaction({ ...params, feeLimit: feeLimitSun });
1121
+ }
1122
+ return this.signTransaction(params);
1123
+ }
1124
+ /**
1125
+ * Register an external energy delegation provider.
1126
+ *
1127
+ * Energy providers can delegate bandwidth and energy to this account
1128
+ * to reduce TRX costs for TRC20 transfers.
1129
+ *
1130
+ * @param provider - Energy delegation provider
1131
+ */
1132
+ registerEnergyProvider(provider) {
1133
+ this._energyProvider = provider;
1134
+ }
1135
+ /**
1136
+ * Get the registered energy provider, if any
1137
+ */
1138
+ getEnergyProvider() {
1139
+ return this._energyProvider;
1140
+ }
418
1141
  /**
419
1142
  * Build a TRC20 transfer transaction
420
1143
  */
@@ -499,82 +1222,228 @@ async function createWDKTronSigner(account, rpcUrl) {
499
1222
  return adapter;
500
1223
  }
501
1224
 
502
- // src/cache.ts
503
- var DEFAULT_CACHE_CONFIG = {
504
- defaultTTL: 3e4,
505
- // 30 seconds
506
- maxSize: 1e3,
507
- refreshOnAccess: false
508
- };
509
- var TTLCache = class {
510
- _cache = /* @__PURE__ */ new Map();
511
- _config;
512
- _cleanupInterval = null;
513
- constructor(config = {}) {
514
- this._config = { ...DEFAULT_CACHE_CONFIG, ...config };
515
- if (this._config.maxSize > 0) {
516
- this._startCleanup();
1225
+ // src/adapters/spark-adapter.ts
1226
+ var WDKSparkSignerAdapter = class {
1227
+ _account;
1228
+ _address = null;
1229
+ _initialized = false;
1230
+ constructor(account) {
1231
+ if (!account) {
1232
+ throw new Error("Spark wallet account is required");
517
1233
  }
1234
+ this._account = account;
518
1235
  }
519
1236
  /**
520
- * Get a value from the cache
521
- *
522
- * @param key - Cache key
523
- * @returns The cached value or undefined if not found/expired
1237
+ * Get the wallet address
1238
+ * @throws Error if not initialized
524
1239
  */
525
- get(key) {
526
- const entry = this._cache.get(key);
527
- if (!entry) {
528
- return void 0;
529
- }
530
- if (Date.now() > entry.expiresAt) {
531
- this._cache.delete(key);
532
- return void 0;
533
- }
534
- if (this._config.refreshOnAccess) {
535
- entry.expiresAt = Date.now() + this._config.defaultTTL;
1240
+ get address() {
1241
+ if (!this._address) {
1242
+ throw new Error(
1243
+ "Spark signer not initialized. Call initialize() first or use createWDKSparkSigner()."
1244
+ );
536
1245
  }
537
- return entry.value;
1246
+ return this._address;
538
1247
  }
539
1248
  /**
540
- * Set a value in the cache
541
- *
542
- * @param key - Cache key
543
- * @param value - Value to cache
544
- * @param ttl - TTL in milliseconds (optional, uses default if not provided)
1249
+ * Check if the adapter is initialized
545
1250
  */
546
- set(key, value, ttl) {
547
- if (this._cache.size >= this._config.maxSize) {
548
- this._evictOldest();
549
- }
550
- const expiresAt = Date.now() + (ttl ?? this._config.defaultTTL);
551
- this._cache.set(key, { value, expiresAt });
1251
+ get isInitialized() {
1252
+ return this._initialized;
552
1253
  }
553
1254
  /**
554
- * Check if a key exists and is not expired
555
- *
556
- * @param key - Cache key
557
- * @returns true if key exists and is not expired
1255
+ * Initialize the adapter by fetching the address
1256
+ * Must be called before using the signer
558
1257
  */
559
- has(key) {
560
- const entry = this._cache.get(key);
561
- if (!entry) {
562
- return false;
563
- }
564
- if (Date.now() > entry.expiresAt) {
565
- this._cache.delete(key);
566
- return false;
1258
+ async initialize() {
1259
+ if (this._initialized) {
1260
+ return;
567
1261
  }
568
- return true;
1262
+ this._address = await this._account.getAddress();
1263
+ this._initialized = true;
569
1264
  }
570
1265
  /**
571
- * Delete a key from the cache
572
- *
573
- * @param key - Cache key
574
- * @returns true if key was deleted
1266
+ * Sign a message using the Spark wallet
1267
+ * @param message - Message to sign (string or bytes)
1268
+ * @returns Signature string
575
1269
  */
576
- delete(key) {
577
- return this._cache.delete(key);
1270
+ async signMessage(message) {
1271
+ return this._account.signMessage(message);
1272
+ }
1273
+ /**
1274
+ * Get the wallet balance in satoshis
1275
+ */
1276
+ async getBalance() {
1277
+ return this._account.getBalance();
1278
+ }
1279
+ /**
1280
+ * Send a transaction via the Spark network
1281
+ * @param params - Transaction parameters
1282
+ * @returns Transaction result with hash
1283
+ */
1284
+ async sendTransaction(params) {
1285
+ return this._account.sendTransaction(params);
1286
+ }
1287
+ };
1288
+ async function createWDKSparkSigner(account) {
1289
+ const adapter = new WDKSparkSignerAdapter(account);
1290
+ await adapter.initialize();
1291
+ return adapter;
1292
+ }
1293
+
1294
+ // src/adapters/btc-adapter.ts
1295
+ var WDKBtcSignerAdapter = class {
1296
+ _account;
1297
+ _address = null;
1298
+ _initialized = false;
1299
+ constructor(account) {
1300
+ if (!account) {
1301
+ throw new Error("WDK Bitcoin account is required");
1302
+ }
1303
+ this._account = account;
1304
+ }
1305
+ /**
1306
+ * Get the wallet address
1307
+ * @throws Error if not initialized
1308
+ */
1309
+ get address() {
1310
+ if (!this._address) {
1311
+ throw new Error(
1312
+ "Bitcoin signer not initialized. Call initialize() first or use createWDKBtcSigner()."
1313
+ );
1314
+ }
1315
+ return this._address;
1316
+ }
1317
+ /**
1318
+ * Check if the adapter is initialized
1319
+ */
1320
+ get isInitialized() {
1321
+ return this._initialized;
1322
+ }
1323
+ /**
1324
+ * Initialize the adapter by fetching the address
1325
+ * Must be called before using the signer
1326
+ */
1327
+ async initialize() {
1328
+ if (this._initialized) {
1329
+ return;
1330
+ }
1331
+ this._address = await this._account.getAddress();
1332
+ this._initialized = true;
1333
+ }
1334
+ /**
1335
+ * Sign a message using the Bitcoin wallet
1336
+ * @param message - Message string to sign
1337
+ * @returns Signature string
1338
+ */
1339
+ async signMessage(message) {
1340
+ return this._account.signMessage(message);
1341
+ }
1342
+ /**
1343
+ * Sign a Partially Signed Bitcoin Transaction (PSBT)
1344
+ * @param psbt - PSBT bytes to sign
1345
+ * @returns Signed PSBT bytes
1346
+ */
1347
+ async signPsbt(psbt) {
1348
+ return this._account.signPsbt(psbt);
1349
+ }
1350
+ /**
1351
+ * Get the wallet balance in satoshis
1352
+ */
1353
+ async getBalance() {
1354
+ return this._account.getBalance();
1355
+ }
1356
+ /**
1357
+ * Send a Bitcoin transaction
1358
+ * @param params - Transaction parameters
1359
+ * @returns Transaction hash
1360
+ */
1361
+ async sendTransaction(params) {
1362
+ return this._account.sendTransaction(params);
1363
+ }
1364
+ };
1365
+ async function createWDKBtcSigner(account) {
1366
+ const adapter = new WDKBtcSignerAdapter(account);
1367
+ await adapter.initialize();
1368
+ return adapter;
1369
+ }
1370
+
1371
+ // src/cache.ts
1372
+ var DEFAULT_CACHE_CONFIG = {
1373
+ defaultTTL: 3e4,
1374
+ // 30 seconds
1375
+ maxSize: 1e3,
1376
+ refreshOnAccess: false
1377
+ };
1378
+ var TTLCache = class {
1379
+ _cache = /* @__PURE__ */ new Map();
1380
+ _config;
1381
+ _cleanupInterval = null;
1382
+ constructor(config = {}) {
1383
+ this._config = { ...DEFAULT_CACHE_CONFIG, ...config };
1384
+ if (this._config.maxSize > 0) {
1385
+ this._startCleanup();
1386
+ }
1387
+ }
1388
+ /**
1389
+ * Get a value from the cache
1390
+ *
1391
+ * @param key - Cache key
1392
+ * @returns The cached value or undefined if not found/expired
1393
+ */
1394
+ get(key) {
1395
+ const entry = this._cache.get(key);
1396
+ if (!entry) {
1397
+ return void 0;
1398
+ }
1399
+ if (Date.now() > entry.expiresAt) {
1400
+ this._cache.delete(key);
1401
+ return void 0;
1402
+ }
1403
+ if (this._config.refreshOnAccess) {
1404
+ entry.expiresAt = Date.now() + this._config.defaultTTL;
1405
+ }
1406
+ return entry.value;
1407
+ }
1408
+ /**
1409
+ * Set a value in the cache
1410
+ *
1411
+ * @param key - Cache key
1412
+ * @param value - Value to cache
1413
+ * @param ttl - TTL in milliseconds (optional, uses default if not provided)
1414
+ */
1415
+ set(key, value, ttl) {
1416
+ if (this._cache.size >= this._config.maxSize) {
1417
+ this._evictOldest();
1418
+ }
1419
+ const expiresAt = Date.now() + (ttl ?? this._config.defaultTTL);
1420
+ this._cache.set(key, { value, expiresAt });
1421
+ }
1422
+ /**
1423
+ * Check if a key exists and is not expired
1424
+ *
1425
+ * @param key - Cache key
1426
+ * @returns true if key exists and is not expired
1427
+ */
1428
+ has(key) {
1429
+ const entry = this._cache.get(key);
1430
+ if (!entry) {
1431
+ return false;
1432
+ }
1433
+ if (Date.now() > entry.expiresAt) {
1434
+ this._cache.delete(key);
1435
+ return false;
1436
+ }
1437
+ return true;
1438
+ }
1439
+ /**
1440
+ * Delete a key from the cache
1441
+ *
1442
+ * @param key - Cache key
1443
+ * @returns true if key was deleted
1444
+ */
1445
+ delete(key) {
1446
+ return this._cache.delete(key);
578
1447
  }
579
1448
  /**
580
1449
  * Delete all keys matching a prefix
@@ -1117,6 +1986,145 @@ var CHAIN_TOKENS = {
1117
1986
  }
1118
1987
  ]
1119
1988
  };
1989
+ var CHAIN_REGISTRY = {
1990
+ // --- EVM chains (derived from existing constants) ---
1991
+ ethereum: {
1992
+ family: "evm",
1993
+ chainId: 1,
1994
+ caip2: "eip155:1",
1995
+ rpcEndpoints: ["https://eth.drpc.org"],
1996
+ tokens: (CHAIN_TOKENS.ethereum ?? []).map((t) => ({
1997
+ address: t.address,
1998
+ symbol: t.symbol,
1999
+ decimals: t.decimals
2000
+ }))
2001
+ },
2002
+ arbitrum: {
2003
+ family: "evm",
2004
+ chainId: 42161,
2005
+ caip2: "eip155:42161",
2006
+ rpcEndpoints: ["https://arb1.arbitrum.io/rpc"],
2007
+ tokens: (CHAIN_TOKENS.arbitrum ?? []).map((t) => ({
2008
+ address: t.address,
2009
+ symbol: t.symbol,
2010
+ decimals: t.decimals
2011
+ }))
2012
+ },
2013
+ base: {
2014
+ family: "evm",
2015
+ chainId: 8453,
2016
+ caip2: "eip155:8453",
2017
+ rpcEndpoints: ["https://mainnet.base.org"],
2018
+ tokens: (CHAIN_TOKENS.base ?? []).map((t) => ({
2019
+ address: t.address,
2020
+ symbol: t.symbol,
2021
+ decimals: t.decimals
2022
+ }))
2023
+ },
2024
+ ink: {
2025
+ family: "evm",
2026
+ chainId: 57073,
2027
+ caip2: "eip155:57073",
2028
+ rpcEndpoints: ["https://rpc-gel.inkonchain.com"],
2029
+ tokens: (CHAIN_TOKENS.ink ?? []).map((t) => ({
2030
+ address: t.address,
2031
+ symbol: t.symbol,
2032
+ decimals: t.decimals
2033
+ }))
2034
+ },
2035
+ berachain: {
2036
+ family: "evm",
2037
+ chainId: 80094,
2038
+ caip2: "eip155:80094",
2039
+ rpcEndpoints: [],
2040
+ tokens: (CHAIN_TOKENS.berachain ?? []).map((t) => ({
2041
+ address: t.address,
2042
+ symbol: t.symbol,
2043
+ decimals: t.decimals
2044
+ }))
2045
+ },
2046
+ unichain: {
2047
+ family: "evm",
2048
+ chainId: 130,
2049
+ caip2: "eip155:130",
2050
+ rpcEndpoints: [],
2051
+ tokens: (CHAIN_TOKENS.unichain ?? []).map((t) => ({
2052
+ address: t.address,
2053
+ symbol: t.symbol,
2054
+ decimals: t.decimals
2055
+ }))
2056
+ },
2057
+ optimism: {
2058
+ family: "evm",
2059
+ chainId: 10,
2060
+ caip2: "eip155:10",
2061
+ rpcEndpoints: ["https://mainnet.optimism.io"],
2062
+ tokens: (CHAIN_TOKENS.optimism ?? []).map((t) => ({
2063
+ address: t.address,
2064
+ symbol: t.symbol,
2065
+ decimals: t.decimals
2066
+ }))
2067
+ },
2068
+ polygon: {
2069
+ family: "evm",
2070
+ chainId: 137,
2071
+ caip2: "eip155:137",
2072
+ rpcEndpoints: ["https://polygon-rpc.com"],
2073
+ tokens: (CHAIN_TOKENS.polygon ?? []).map((t) => ({
2074
+ address: t.address,
2075
+ symbol: t.symbol,
2076
+ decimals: t.decimals
2077
+ }))
2078
+ },
2079
+ // --- Non-EVM chains ---
2080
+ ton: {
2081
+ family: "ton",
2082
+ caip2: "ton:mainnet",
2083
+ rpcEndpoints: ["https://toncenter.com/api/v2/jsonRPC"],
2084
+ tokens: [
2085
+ {
2086
+ address: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
2087
+ symbol: "USDT",
2088
+ decimals: 6
2089
+ }
2090
+ ]
2091
+ },
2092
+ tron: {
2093
+ family: "tron",
2094
+ caip2: "tron:mainnet",
2095
+ rpcEndpoints: ["https://api.trongrid.io"],
2096
+ tokens: [
2097
+ {
2098
+ address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
2099
+ symbol: "USDT",
2100
+ decimals: 6
2101
+ }
2102
+ ]
2103
+ },
2104
+ solana: {
2105
+ family: "svm",
2106
+ caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
2107
+ rpcEndpoints: ["https://api.mainnet-beta.solana.com"],
2108
+ tokens: [
2109
+ {
2110
+ address: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
2111
+ symbol: "USDT",
2112
+ decimals: 6
2113
+ }
2114
+ ]
2115
+ }
2116
+ };
2117
+ function getRegistryByCaip2(caip2) {
2118
+ for (const entry of Object.values(CHAIN_REGISTRY)) {
2119
+ if (entry.caip2 === caip2) {
2120
+ return entry;
2121
+ }
2122
+ }
2123
+ return void 0;
2124
+ }
2125
+ function getChainsByFamily(family) {
2126
+ return Object.entries(CHAIN_REGISTRY).filter(([, entry]) => entry.family === family).map(([name]) => name);
2127
+ }
1120
2128
  function normalizeChainConfig(chainName, config) {
1121
2129
  const defaultConfig = DEFAULT_CHAINS[chainName];
1122
2130
  if (typeof config === "string") {
@@ -1127,8 +2135,9 @@ function normalizeChainConfig(chainName, config) {
1127
2135
  name: chainName
1128
2136
  };
1129
2137
  }
2138
+ const resolvedProvider = Array.isArray(config.provider) ? config.provider[0] : config.provider;
1130
2139
  return {
1131
- provider: config.provider,
2140
+ provider: resolvedProvider,
1132
2141
  chainId: config.chainId ?? defaultConfig?.chainId ?? 1,
1133
2142
  network: config.network ?? defaultConfig?.network ?? `eip155:${config.chainId}`,
1134
2143
  name: chainName
@@ -1143,6 +2152,11 @@ function getChainFromNetwork(network) {
1143
2152
  return chain;
1144
2153
  }
1145
2154
  }
2155
+ for (const [chain, entry] of Object.entries(CHAIN_REGISTRY)) {
2156
+ if (entry.caip2 === network) {
2157
+ return chain;
2158
+ }
2159
+ }
1146
2160
  return void 0;
1147
2161
  }
1148
2162
  function getChainId(chain) {
@@ -1805,6 +2819,65 @@ var WDKSigner = class {
1805
2819
  );
1806
2820
  }
1807
2821
  }
2822
+ /**
2823
+ * Sign an EIP-2612 permit for gasless token approvals
2824
+ *
2825
+ * @param params - Permit parameters
2826
+ * @returns The permit signature components (v, r, s)
2827
+ * @throws {SigningError} If signing fails
2828
+ */
2829
+ async signPermit(params) {
2830
+ if (!params.token || !params.token.startsWith("0x")) {
2831
+ throw new SigningError(
2832
+ 4003 /* INVALID_TYPED_DATA */,
2833
+ `Invalid token address: ${params.token}`,
2834
+ { operation: "signTypedData", context: { chain: this._chain } }
2835
+ );
2836
+ }
2837
+ if (!params.spender || !params.spender.startsWith("0x")) {
2838
+ throw new SigningError(
2839
+ 4003 /* INVALID_TYPED_DATA */,
2840
+ `Invalid spender address: ${params.spender}`,
2841
+ { operation: "signTypedData", context: { chain: this._chain } }
2842
+ );
2843
+ }
2844
+ const chainId = this.getChainId();
2845
+ const nonce = params.nonce ?? 0n;
2846
+ const typedData = {
2847
+ domain: {
2848
+ name: params.tokenName ?? "Tether USD",
2849
+ version: params.tokenVersion ?? "1",
2850
+ chainId: BigInt(chainId),
2851
+ verifyingContract: params.token
2852
+ },
2853
+ types: {
2854
+ Permit: [
2855
+ { name: "owner", type: "address" },
2856
+ { name: "spender", type: "address" },
2857
+ { name: "value", type: "uint256" },
2858
+ { name: "nonce", type: "uint256" },
2859
+ { name: "deadline", type: "uint256" }
2860
+ ]
2861
+ },
2862
+ primaryType: "Permit",
2863
+ message: {
2864
+ owner: this.address,
2865
+ spender: params.spender,
2866
+ value: params.value.toString(),
2867
+ nonce: nonce.toString(),
2868
+ deadline: params.deadline.toString()
2869
+ }
2870
+ };
2871
+ const signature = await this.signTypedData(typedData);
2872
+ const sigHex = signature.slice(2);
2873
+ const r = `0x${sigHex.slice(0, 64)}`;
2874
+ const s = `0x${sigHex.slice(64, 128)}`;
2875
+ let v = parseInt(sigHex.slice(128, 130), 16);
2876
+ if (v < 27) {
2877
+ v += 27;
2878
+ }
2879
+ return { v, r, s };
2880
+ }
1808
2881
  /**
1809
2882
  * Send a transaction (for advanced use cases)
1810
2883
  *
@@ -1875,34 +2948,429 @@ var MockWDKSigner = class {
1875
2948
 
1876
2949
  // src/t402wdk.ts
1877
2950
  var import_evm = require("@t402/evm");
1878
- var T402WDK = class _T402WDK {
1879
- _wdk = null;
1880
- _normalizedChains = /* @__PURE__ */ new Map();
1881
- _seedPhrase;
1882
- _signerCache = /* @__PURE__ */ new Map();
1883
- _balanceCache;
1884
- _initializationError = null;
1885
- // WDK module references (set via registerWDK)
1886
- static _WDK = null;
1887
- static _WalletManagerEvm = null;
1888
- static _BridgeUsdt0Evm = null;
1889
- // Multi-chain wallet module storage
1890
- static _WalletModules = {};
1891
- static _ProtocolModules = {};
1892
- // Multi-chain signer caches
1893
- _tonSignerCache = /* @__PURE__ */ new Map();
1894
- _svmSignerCache = /* @__PURE__ */ new Map();
1895
- _tronSignerCache = /* @__PURE__ */ new Map();
1896
- /**
1897
- * Register the Tether WDK modules
1898
- *
1899
- * This must be called before creating T402WDK instances if you want
1900
- * to use the actual WDK. Otherwise, a mock implementation is used.
1901
- *
1902
- * Supports two registration patterns:
2951
+
2952
+ // src/pricing.ts
2953
+ var _registeredPricingProvider = null;
2954
+ function registerPricingProvider(provider) {
2955
+ _registeredPricingProvider = provider;
2956
+ }
2957
+ function getPricingProvider() {
2958
+ return _registeredPricingProvider;
2959
+ }
2960
+ function isPricingProviderRegistered() {
2961
+ return _registeredPricingProvider !== null;
2962
+ }
2963
+ var STABLECOIN_SYMBOLS = /* @__PURE__ */ new Set(["USDT", "USDT0", "USDC", "DAI", "BUSD"]);
2964
+ var DEFAULT_TTL = 6e4;
2965
+ var DEFAULT_FIAT = ["USD", "EUR", "GBP", "JPY"];
2966
+ function createWdkMoneyParser(config) {
2967
+ const cacheTTL = config?.cacheTTL ?? DEFAULT_TTL;
2968
+ const supportedFiat = new Set(config?.supportedFiat ?? DEFAULT_FIAT);
2969
+ const cache = /* @__PURE__ */ new Map();
2970
+ return async (amount, network) => {
2971
+ if (!Number.isFinite(amount) || amount <= 0) return null;
2972
+ const chain = getChainFromNetwork(network);
2973
+ if (!chain) return null;
2974
+ const tokenInfo = getPreferredToken(chain);
2975
+ if (!tokenInfo) return null;
2976
+ if (STABLECOIN_SYMBOLS.has(tokenInfo.symbol.toUpperCase())) {
2977
+ return {
2978
+ amount: toAtomicUnits(amount, tokenInfo.decimals),
2979
+ asset: tokenInfo.address
2980
+ };
2981
+ }
2982
+ const currency = "USD";
2983
+ if (!supportedFiat.has(currency)) return null;
2984
+ const cacheKey = `${currency}_${tokenInfo.symbol}`;
2985
+ const cached = cache.get(cacheKey);
2986
+ const now = Date.now();
2987
+ let rate;
2988
+ if (cached && now - cached.fetchedAt < cacheTTL) {
2989
+ rate = cached.rate;
2990
+ } else {
2991
+ rate = await fetchRate(currency, tokenInfo.symbol);
2992
+ cache.set(cacheKey, { rate, fetchedAt: now });
2993
+ }
2994
+ const convertedAmount = amount * rate;
2995
+ return {
2996
+ amount: toAtomicUnits(convertedAmount, tokenInfo.decimals),
2997
+ asset: tokenInfo.address
2998
+ };
2999
+ };
3000
+ }
3001
+ function toAtomicUnits(amount, decimals) {
3002
+ const factor = 10 ** decimals;
3003
+ const atomic = Math.round(amount * factor);
3004
+ return atomic.toString();
3005
+ }
3006
+ function resolveAssetForNetwork(token, network) {
3007
+ const chain = getChainFromNetwork(network);
3008
+ if (!chain) return null;
3009
+ const upper = token.toUpperCase();
3010
+ if (upper === "USDT0" || upper === "USDT") {
3011
+ return USDT0_ADDRESSES[chain] ?? null;
3012
+ }
3013
+ if (upper === "USDC") {
3014
+ return USDC_ADDRESSES[chain] ?? null;
3015
+ }
3016
+ return null;
3017
+ }
3018
+ async function fetchRate(fromCurrency, toToken) {
3019
+ if (_registeredPricingProvider) {
3020
+ try {
3021
+ return await _registeredPricingProvider.getRate(fromCurrency, toToken);
3022
+ } catch {
3023
+ }
3024
+ }
3025
+ if (fromCurrency.toUpperCase() === "USD") {
3026
+ return 1;
3027
+ }
3028
+ const placeholderRates = {
3029
+ EUR: 1.08,
3030
+ GBP: 1.27,
3031
+ JPY: 67e-4
3032
+ };
3033
+ return placeholderRates[fromCurrency.toUpperCase()] ?? 1;
3034
+ }
3035
+
3036
+ // src/failover.ts
3037
+ var DEFAULT_HEALTH_CHECK_INTERVAL = 3e4;
3038
+ var DEFAULT_REQUEST_TIMEOUT = 5e3;
3039
+ var DEFAULT_MAX_FAILURES = 3;
3040
+ var FailoverProvider = class {
3041
+ providers;
3042
+ currentIndex = 0;
3043
+ healthCheckTimer;
3044
+ maxFailures;
3045
+ requestTimeout;
3046
+ constructor(config) {
3047
+ if (!config.urls || config.urls.length === 0) {
3048
+ throw new Error("FailoverProvider requires at least one URL");
3049
+ }
3050
+ this.maxFailures = config.maxFailures ?? DEFAULT_MAX_FAILURES;
3051
+ this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
3052
+ this.providers = config.urls.map((url) => ({
3053
+ url,
3054
+ healthy: true,
3055
+ lastChecked: Date.now(),
3056
+ consecutiveFailures: 0
3057
+ }));
3058
+ const interval = config.healthCheckInterval ?? DEFAULT_HEALTH_CHECK_INTERVAL;
3059
+ if (interval > 0) {
3060
+ this.startHealthChecks(interval);
3061
+ }
3062
+ }
3063
+ /**
3064
+ * Get current active RPC URL
3065
+ */
3066
+ getCurrentUrl() {
3067
+ return this.providers[this.currentIndex].url;
3068
+ }
3069
+ /**
3070
+ * Report a failure on the current URL.
3071
+ * Auto-switches to next healthy provider if failure threshold is reached.
1903
3072
  *
1904
- * 1. Legacy (EVM-only):
1905
- * ```typescript
3073
+ * @returns The new URL if switched, or null if no switch occurred
3074
+ */
3075
+ reportFailure() {
3076
+ const provider = this.providers[this.currentIndex];
3077
+ provider.consecutiveFailures++;
3078
+ provider.lastChecked = Date.now();
3079
+ if (provider.consecutiveFailures >= this.maxFailures) {
3080
+ provider.healthy = false;
3081
+ return this.switchToNext();
3082
+ }
3083
+ return null;
3084
+ }
3085
+ /**
3086
+ * Report success on the current URL, reset failure counter.
3087
+ */
3088
+ reportSuccess() {
3089
+ const provider = this.providers[this.currentIndex];
3090
+ provider.consecutiveFailures = 0;
3091
+ provider.healthy = true;
3092
+ provider.lastChecked = Date.now();
3093
+ }
3094
+ /**
3095
+ * Get all provider statuses
3096
+ */
3097
+ getStatus() {
3098
+ return this.providers.map((p) => ({ ...p }));
3099
+ }
3100
+ /**
3101
+ * Force switch to next healthy provider.
3102
+ *
3103
+ * @returns The new URL, or null if no healthy providers available
3104
+ */
3105
+ switchToNext() {
3106
+ const startIndex = this.currentIndex;
3107
+ for (let i = 1; i <= this.providers.length; i++) {
3108
+ const nextIndex = (startIndex + i) % this.providers.length;
3109
+ if (this.providers[nextIndex].healthy) {
3110
+ this.currentIndex = nextIndex;
3111
+ return this.providers[nextIndex].url;
3112
+ }
3113
+ }
3114
+ return null;
3115
+ }
3116
+ /**
3117
+ * Get the request timeout in milliseconds
3118
+ */
3119
+ getRequestTimeout() {
3120
+ return this.requestTimeout;
3121
+ }
3122
+ /**
3123
+ * Stop health checks and clean up resources
3124
+ */
3125
+ dispose() {
3126
+ if (this.healthCheckTimer) {
3127
+ clearInterval(this.healthCheckTimer);
3128
+ this.healthCheckTimer = void 0;
3129
+ }
3130
+ }
3131
+ startHealthChecks(interval) {
3132
+ this.healthCheckTimer = setInterval(() => {
3133
+ for (const provider of this.providers) {
3134
+ if (!provider.healthy) {
3135
+ this.checkHealth(provider);
3136
+ }
3137
+ }
3138
+ }, interval);
3139
+ if (this.healthCheckTimer.unref) {
3140
+ this.healthCheckTimer.unref();
3141
+ }
3142
+ }
3143
+ async checkHealth(provider) {
3144
+ try {
3145
+ const controller = new AbortController();
3146
+ const timeout = setTimeout(() => controller.abort(), this.requestTimeout);
3147
+ const response = await fetch(provider.url, {
3148
+ method: "POST",
3149
+ headers: { "Content-Type": "application/json" },
3150
+ body: JSON.stringify({
3151
+ jsonrpc: "2.0",
3152
+ method: "eth_chainId",
3153
+ params: [],
3154
+ id: 1
3155
+ }),
3156
+ signal: controller.signal
3157
+ });
3158
+ clearTimeout(timeout);
3159
+ if (response.ok) {
3160
+ provider.healthy = true;
3161
+ provider.consecutiveFailures = 0;
3162
+ provider.lastChecked = Date.now();
3163
+ return true;
3164
+ }
3165
+ } catch {
3166
+ }
3167
+ provider.lastChecked = Date.now();
3168
+ return false;
3169
+ }
3170
+ };
3171
+ function createFailoverProvider(config) {
3172
+ if (typeof config === "string") return null;
3173
+ if (Array.isArray(config)) return new FailoverProvider({ urls: config });
3174
+ return new FailoverProvider(config);
3175
+ }
3176
+ function resolveRpcUrl(config) {
3177
+ if (typeof config === "string") return config;
3178
+ if (Array.isArray(config)) return config[0];
3179
+ return config.urls[0];
3180
+ }
3181
+
3182
+ // src/t402wdk.ts
3183
+ var SUPPORTED_WDK_RANGE = ">=1.0.0-beta.5 <2.0.0";
3184
+ function parseSemver(version) {
3185
+ const match = version.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
3186
+ if (!match) return null;
3187
+ return {
3188
+ major: parseInt(match[1], 10),
3189
+ minor: parseInt(match[2], 10),
3190
+ patch: parseInt(match[3], 10),
3191
+ prerelease: match[4] ?? ""
3192
+ };
3193
+ }
3194
+ function comparePrereleases(a, b) {
3195
+ if (a === b) return 0;
3196
+ if (a === "" && b !== "") return 1;
3197
+ if (a !== "" && b === "") return -1;
3198
+ const aParts = a.split(".");
3199
+ const bParts = b.split(".");
3200
+ const len = Math.max(aParts.length, bParts.length);
3201
+ for (let i = 0; i < len; i++) {
3202
+ const ap = aParts[i] ?? "";
3203
+ const bp = bParts[i] ?? "";
3204
+ const aNum = /^\d+$/.test(ap);
3205
+ const bNum = /^\d+$/.test(bp);
3206
+ if (aNum && bNum) {
3207
+ const diff = parseInt(ap, 10) - parseInt(bp, 10);
3208
+ if (diff !== 0) return diff;
3209
+ } else if (aNum !== bNum) {
3210
+ return aNum ? -1 : 1;
3211
+ } else {
3212
+ if (ap < bp) return -1;
3213
+ if (ap > bp) return 1;
3214
+ }
3215
+ }
3216
+ return 0;
3217
+ }
3218
+ function compareSemver(a, b) {
3219
+ const pa = parseSemver(a);
3220
+ const pb = parseSemver(b);
3221
+ if (!pa || !pb) return 0;
3222
+ if (pa.major !== pb.major) return pa.major - pb.major > 0 ? 1 : -1;
3223
+ if (pa.minor !== pb.minor) return pa.minor - pb.minor > 0 ? 1 : -1;
3224
+ if (pa.patch !== pb.patch) return pa.patch - pb.patch > 0 ? 1 : -1;
3225
+ return comparePrereleases(pa.prerelease, pb.prerelease);
3226
+ }
3227
+ function satisfiesSemverRange(version, range) {
3228
+ const parsed = parseSemver(version);
3229
+ if (!parsed) return false;
3230
+ const constraints = range.trim().split(/\s+/);
3231
+ for (const constraint of constraints) {
3232
+ const match = constraint.match(/^(>=|<=|>|<|=)(.+)$/);
3233
+ if (!match) continue;
3234
+ const [, op, target] = match;
3235
+ const cmp = compareSemver(version, target);
3236
+ switch (op) {
3237
+ case ">=":
3238
+ if (cmp < 0) return false;
3239
+ break;
3240
+ case ">":
3241
+ if (cmp <= 0) return false;
3242
+ break;
3243
+ case "<=":
3244
+ if (cmp > 0) return false;
3245
+ break;
3246
+ case "<":
3247
+ if (cmp >= 0) return false;
3248
+ break;
3249
+ case "=":
3250
+ if (cmp !== 0) return false;
3251
+ break;
3252
+ }
3253
+ }
3254
+ return true;
3255
+ }
3256
+ var T402WDK = class _T402WDK {
3257
+ _wdk = null;
3258
+ _normalizedChains = /* @__PURE__ */ new Map();
3259
+ _seedPhrase;
3260
+ _signerCache = /* @__PURE__ */ new Map();
3261
+ _balanceCache;
3262
+ _initializationError = null;
3263
+ _events = new T402EventEmitter();
3264
+ _receiptStore = new InMemoryReceiptStore();
3265
+ _disposed = false;
3266
+ // Instance-level module references (#204 multi-instance)
3267
+ _wdkConstructor = null;
3268
+ _walletManagerEvm = null;
3269
+ _bridgeUsdt0Evm = null;
3270
+ _walletModules = {};
3271
+ _protocolModules = {};
3272
+ _fiatOnRampProvider = null;
3273
+ _middlewares = /* @__PURE__ */ new Map();
3274
+ // Retry config (#202 network resilience)
3275
+ _retryConfig;
3276
+ // Failover providers (#195)
3277
+ _failoverProviders = /* @__PURE__ */ new Map();
3278
+ // Static defaults for backward compatibility (#204)
3279
+ static _defaultModules = {};
3280
+ // Legacy static accessors for tests that access _WDK, _WalletManagerEvm, etc.
3281
+ static get _WDK() {
3282
+ return _T402WDK._defaultModules.wdk ?? null;
3283
+ }
3284
+ static set _WDK(val) {
3285
+ if (val === null) {
3286
+ delete _T402WDK._defaultModules.wdk;
3287
+ } else {
3288
+ _T402WDK._defaultModules.wdk = val;
3289
+ }
3290
+ }
3291
+ static get _WalletManagerEvm() {
3292
+ return _T402WDK._defaultModules.walletManagerEvm ?? null;
3293
+ }
3294
+ static set _WalletManagerEvm(val) {
3295
+ if (val === null) {
3296
+ delete _T402WDK._defaultModules.walletManagerEvm;
3297
+ if (_T402WDK._defaultModules.wallets) {
3298
+ delete _T402WDK._defaultModules.wallets.evm;
3299
+ }
3300
+ } else {
3301
+ _T402WDK._defaultModules.walletManagerEvm = val;
3302
+ if (!_T402WDK._defaultModules.wallets) {
3303
+ _T402WDK._defaultModules.wallets = {};
3304
+ }
3305
+ _T402WDK._defaultModules.wallets.evm = val;
3306
+ }
3307
+ }
3308
+ static get _BridgeUsdt0Evm() {
3309
+ return _T402WDK._defaultModules.bridgeUsdt0Evm ?? null;
3310
+ }
3311
+ static set _BridgeUsdt0Evm(val) {
3312
+ if (val === null) {
3313
+ delete _T402WDK._defaultModules.bridgeUsdt0Evm;
3314
+ if (_T402WDK._defaultModules.protocols) {
3315
+ delete _T402WDK._defaultModules.protocols.bridgeUsdt0Evm;
3316
+ }
3317
+ } else {
3318
+ _T402WDK._defaultModules.bridgeUsdt0Evm = val;
3319
+ if (!_T402WDK._defaultModules.protocols) {
3320
+ _T402WDK._defaultModules.protocols = {};
3321
+ }
3322
+ _T402WDK._defaultModules.protocols.bridgeUsdt0Evm = val;
3323
+ }
3324
+ }
3325
+ static get _WalletModules() {
3326
+ return _T402WDK._defaultModules.wallets ?? {};
3327
+ }
3328
+ static set _WalletModules(val) {
3329
+ _T402WDK._defaultModules.wallets = val;
3330
+ }
3331
+ static get _ProtocolModules() {
3332
+ return _T402WDK._defaultModules.protocols ?? {};
3333
+ }
3334
+ static set _ProtocolModules(val) {
3335
+ _T402WDK._defaultModules.protocols = val;
3336
+ }
3337
+ static get _fiatOnRampProvider() {
3338
+ return _T402WDK._defaultModules.fiatOnRampProvider ?? null;
3339
+ }
3340
+ static set _fiatOnRampProvider(val) {
3341
+ if (val === null) {
3342
+ delete _T402WDK._defaultModules.fiatOnRampProvider;
3343
+ } else {
3344
+ _T402WDK._defaultModules.fiatOnRampProvider = val;
3345
+ }
3346
+ }
3347
+ static get _middlewares() {
3348
+ if (!_T402WDK._defaultModules.middlewares) {
3349
+ _T402WDK._defaultModules.middlewares = /* @__PURE__ */ new Map();
3350
+ }
3351
+ return _T402WDK._defaultModules.middlewares;
3352
+ }
3353
+ static set _middlewares(val) {
3354
+ _T402WDK._defaultModules.middlewares = val;
3355
+ }
3356
+ // HD path-derived signer cache
3357
+ _pathSignerCache = /* @__PURE__ */ new Map();
3358
+ // Multi-chain signer caches
3359
+ _tonSignerCache = /* @__PURE__ */ new Map();
3360
+ _svmSignerCache = /* @__PURE__ */ new Map();
3361
+ _tronSignerCache = /* @__PURE__ */ new Map();
3362
+ _sparkSignerCache = /* @__PURE__ */ new Map();
3363
+ _btcSignerCache = /* @__PURE__ */ new Map();
3364
+ /**
3365
+ * Register the Tether WDK modules
3366
+ *
3367
+ * This must be called before creating T402WDK instances if you want
3368
+ * to use the actual WDK. Otherwise, a mock implementation is used.
3369
+ *
3370
+ * Supports two registration patterns:
3371
+ *
3372
+ * 1. Legacy (EVM-only):
3373
+ * ```typescript
1906
3374
  * T402WDK.registerWDK(WDK, WalletManagerEvm, BridgeUsdt0Evm);
1907
3375
  * ```
1908
3376
  *
@@ -1931,6 +3399,14 @@ var T402WDK = class _T402WDK {
1931
3399
  if (typeof WDK !== "function") {
1932
3400
  throw new WDKInitializationError("WDK must be a constructor function");
1933
3401
  }
3402
+ const wdkVersion = WDK.version;
3403
+ if (wdkVersion && typeof wdkVersion === "string") {
3404
+ if (!satisfiesSemverRange(wdkVersion, SUPPORTED_WDK_RANGE)) {
3405
+ throw new WDKInitializationError(
3406
+ `WDK version ${wdkVersion} is not supported. Required: ${SUPPORTED_WDK_RANGE}`
3407
+ );
3408
+ }
3409
+ }
1934
3410
  _T402WDK._WDK = WDK;
1935
3411
  if (modulesOrWalletManager && typeof modulesOrWalletManager === "object" && ("wallets" in modulesOrWalletManager || "protocols" in modulesOrWalletManager)) {
1936
3412
  const modules = modulesOrWalletManager;
@@ -1981,6 +3457,18 @@ var T402WDK = class _T402WDK {
1981
3457
  static isTronRegistered() {
1982
3458
  return _T402WDK._WalletModules.tron !== void 0;
1983
3459
  }
3460
+ /**
3461
+ * Check if Spark wallet manager is registered
3462
+ */
3463
+ static isSparkRegistered() {
3464
+ return _T402WDK._WalletModules.spark !== void 0;
3465
+ }
3466
+ /**
3467
+ * Check if Bitcoin wallet manager is registered
3468
+ */
3469
+ static isBtcRegistered() {
3470
+ return _T402WDK._WalletModules.btc !== void 0;
3471
+ }
1984
3472
  /**
1985
3473
  * Get all registered wallet modules
1986
3474
  */
@@ -1997,6 +3485,62 @@ var T402WDK = class _T402WDK {
1997
3485
  (key) => _T402WDK._ProtocolModules[key] !== void 0
1998
3486
  );
1999
3487
  }
3488
+ /**
3489
+ * Register a fiat on-ramp provider
3490
+ *
3491
+ * @param provider - A FiatOnRampProvider implementation (e.g., MoonpayOnRampProvider)
3492
+ *
3493
+ * @example
3494
+ * ```typescript
3495
+ * import { T402WDK, MoonpayOnRampProvider } from '@t402/wdk';
3496
+ *
3497
+ * T402WDK.registerFiatOnRamp(new MoonpayOnRampProvider({ apiKey: 'pk_test_...' }));
3498
+ * ```
3499
+ */
3500
+ static registerFiatOnRamp(provider) {
3501
+ if (!provider || typeof provider.getQuote !== "function") {
3502
+ throw new WDKInitializationError("A valid FiatOnRampProvider is required");
3503
+ }
3504
+ _T402WDK._fiatOnRampProvider = provider;
3505
+ }
3506
+ /**
3507
+ * Check if a fiat on-ramp provider is registered
3508
+ */
3509
+ static isFiatOnRampRegistered() {
3510
+ return _T402WDK._fiatOnRampProvider !== null;
3511
+ }
3512
+ /**
3513
+ * Register a pricing provider for fiat-to-crypto rate conversion
3514
+ */
3515
+ static registerPricingProvider(provider) {
3516
+ registerPricingProvider(provider);
3517
+ }
3518
+ /**
3519
+ * Check if a pricing provider is registered
3520
+ */
3521
+ static isPricingProviderRegistered() {
3522
+ return isPricingProviderRegistered();
3523
+ }
3524
+ /**
3525
+ * Register a middleware for a chain
3526
+ */
3527
+ static registerMiddleware(chain, fn) {
3528
+ const existing = _T402WDK._middlewares.get(chain) ?? [];
3529
+ existing.push(fn);
3530
+ _T402WDK._middlewares.set(chain, existing);
3531
+ }
3532
+ /**
3533
+ * Get registered middlewares for a chain
3534
+ */
3535
+ static getMiddlewares(chain) {
3536
+ return _T402WDK._middlewares.get(chain) ?? [];
3537
+ }
3538
+ /**
3539
+ * Clear all middlewares
3540
+ */
3541
+ static clearMiddlewares() {
3542
+ _T402WDK._middlewares.clear();
3543
+ }
2000
3544
  /**
2001
3545
  * Generate a new random seed phrase
2002
3546
  *
@@ -2047,6 +3591,131 @@ var T402WDK = class _T402WDK {
2047
3591
  _T402WDK.registerWDK(WDK, config.modules);
2048
3592
  return new _T402WDK(config.seedPhrase, config.chains, config.options);
2049
3593
  }
3594
+ /**
3595
+ * Auto-discover installed WDK packages using dynamic imports.
3596
+ *
3597
+ * Probes known `@tetherto/wdk-*` packages and returns the ones that
3598
+ * are installed and importable.
3599
+ *
3600
+ * @returns Discovery result with available/unavailable packages and ready-to-use modules config
3601
+ *
3602
+ * @example
3603
+ * ```typescript
3604
+ * const result = await T402WDK.autoDiscover();
3605
+ * console.log('Found:', result.available);
3606
+ * console.log('Missing:', result.unavailable);
3607
+ * ```
3608
+ */
3609
+ static async autoDiscover() {
3610
+ const walletPackages = {
3611
+ evm: "@tetherto/wdk-wallet-evm",
3612
+ solana: "@tetherto/wdk-wallet-solana",
3613
+ ton: "@tetherto/wdk-wallet-ton",
3614
+ tron: "@tetherto/wdk-wallet-tron",
3615
+ btc: "@tetherto/wdk-wallet-btc",
3616
+ spark: "@buildonspark/spark-sdk",
3617
+ evmErc4337: "@tetherto/wdk-wallet-evm-erc-4337",
3618
+ tonGasless: "@tetherto/wdk-wallet-ton-gasless",
3619
+ tronGasfree: "@tetherto/wdk-wallet-tron-gasfree"
3620
+ };
3621
+ const protocolPackages = {
3622
+ bridgeUsdt0Evm: "@tetherto/wdk-protocol-bridge-usdt0-evm",
3623
+ bridgeUsdt0Ton: "@tetherto/wdk-protocol-bridge-usdt0-ton",
3624
+ swapVeloraEvm: "@tetherto/wdk-protocol-swap-velora-evm",
3625
+ lendingAaveEvm: "@tetherto/wdk-protocol-lending-aave-evm"
3626
+ };
3627
+ const available = [];
3628
+ const unavailable = [];
3629
+ const wallets = {};
3630
+ const protocols = {};
3631
+ const walletEntries = Object.entries(walletPackages);
3632
+ const walletResults = await Promise.allSettled(
3633
+ walletEntries.map(async ([key, pkg]) => {
3634
+ const mod = await import(
3635
+ /* @vite-ignore */
3636
+ pkg
3637
+ );
3638
+ return { key, pkg, mod: mod.default ?? mod };
3639
+ })
3640
+ );
3641
+ for (let i = 0; i < walletResults.length; i++) {
3642
+ const result = walletResults[i];
3643
+ if (result.status === "fulfilled") {
3644
+ const { key, pkg, mod } = result.value;
3645
+ wallets[key] = mod;
3646
+ available.push(pkg);
3647
+ } else {
3648
+ unavailable.push(walletEntries[i][1]);
3649
+ }
3650
+ }
3651
+ const protocolEntries = Object.entries(protocolPackages);
3652
+ const protocolResults = await Promise.allSettled(
3653
+ protocolEntries.map(async ([key, pkg]) => {
3654
+ const mod = await import(
3655
+ /* @vite-ignore */
3656
+ pkg
3657
+ );
3658
+ return { key, pkg, mod: mod.default ?? mod };
3659
+ })
3660
+ );
3661
+ for (let i = 0; i < protocolResults.length; i++) {
3662
+ const result = protocolResults[i];
3663
+ if (result.status === "fulfilled") {
3664
+ const { key, pkg, mod } = result.value;
3665
+ protocols[key] = mod;
3666
+ available.push(pkg);
3667
+ } else {
3668
+ unavailable.push(protocolEntries[i][1]);
3669
+ }
3670
+ }
3671
+ return {
3672
+ discovered: { wallets, protocols },
3673
+ available,
3674
+ unavailable
3675
+ };
3676
+ }
3677
+ /**
3678
+ * Auto-discover installed WDK modules, then create a fully configured T402WDK.
3679
+ *
3680
+ * Combines `autoDiscover()` + `create()` in one call. Any explicit
3681
+ * modules you pass in `config.modules` take precedence over discovered ones.
3682
+ *
3683
+ * @param config - Same as `T402WDKCreateConfig` but `modules` is optional/partial
3684
+ * @returns A ready-to-use T402WDK instance
3685
+ *
3686
+ * @example
3687
+ * ```typescript
3688
+ * const wdk = await T402WDK.autoCreate({
3689
+ * seedPhrase: 'your twelve word seed phrase ...',
3690
+ * chains: { arbitrum: 'https://arb1.arbitrum.io/rpc' },
3691
+ * });
3692
+ * ```
3693
+ */
3694
+ static async autoCreate(config) {
3695
+ const { discovered } = await _T402WDK.autoDiscover();
3696
+ const mergedModules = {
3697
+ wallets: { ...discovered.wallets, ...config.modules?.wallets },
3698
+ protocols: { ...discovered.protocols, ...config.modules?.protocols }
3699
+ };
3700
+ let WDKRef;
3701
+ try {
3702
+ const wdkMod = await import(
3703
+ /* @vite-ignore */
3704
+ "@tetherto/wdk"
3705
+ );
3706
+ WDKRef = wdkMod.default ?? wdkMod;
3707
+ } catch {
3708
+ throw new WDKInitializationError(
3709
+ "@tetherto/wdk package not found. Install it with: npm install @tetherto/wdk"
3710
+ );
3711
+ }
3712
+ return _T402WDK.create(WDKRef, {
3713
+ seedPhrase: config.seedPhrase,
3714
+ chains: config.chains,
3715
+ modules: mergedModules,
3716
+ options: config.options
3717
+ });
3718
+ }
2050
3719
  /**
2051
3720
  * Create a T402WDK from a pre-configured @tetherto/wdk instance.
2052
3721
  *
@@ -2066,6 +3735,31 @@ var T402WDK = class _T402WDK {
2066
3735
  instance._initializationError = null;
2067
3736
  return instance;
2068
3737
  }
3738
+ /**
3739
+ * Create a T402WDK instance from an encrypted seed.
3740
+ *
3741
+ * @example
3742
+ * ```typescript
3743
+ * const encrypted = JSON.parse(fs.readFileSync('seed.enc.json', 'utf8'))
3744
+ * const wdk = await T402WDK.fromEncryptedSeed(encrypted, 'my-password', {
3745
+ * arbitrum: 'https://arb1.arbitrum.io/rpc',
3746
+ * })
3747
+ * ```
3748
+ */
3749
+ static async fromEncryptedSeed(encrypted, password, config, options) {
3750
+ const seedPhrase = await decryptSeed(encrypted, password);
3751
+ return new _T402WDK(seedPhrase, config, options);
3752
+ }
3753
+ /**
3754
+ * Encrypt the current seed phrase for secure storage.
3755
+ *
3756
+ * @param password - Password to encrypt with
3757
+ * @returns Encrypted seed data suitable for JSON serialization
3758
+ */
3759
+ async encryptSeed(password) {
3760
+ this.assertNotDisposed();
3761
+ return encryptSeed(this._seedPhrase, password);
3762
+ }
2069
3763
  /**
2070
3764
  * Get all signers as an array ready for T402 HTTP clients.
2071
3765
  *
@@ -2079,6 +3773,7 @@ var T402WDK = class _T402WDK {
2079
3773
  * ```
2080
3774
  */
2081
3775
  async getAllSigners(options) {
3776
+ this.assertNotDisposed();
2082
3777
  const accountIndex = options?.accountIndex ?? 0;
2083
3778
  const schemes = options?.schemes ?? ["exact"];
2084
3779
  const includeNonEvm = options?.includeNonEvm ?? true;
@@ -2102,7 +3797,7 @@ var T402WDK = class _T402WDK {
2102
3797
  if (!includeNonEvm) {
2103
3798
  return entries;
2104
3799
  }
2105
- if (_T402WDK.isTonRegistered()) {
3800
+ if (this._walletModules.ton !== void 0) {
2106
3801
  try {
2107
3802
  const signer = await this.getTonSigner(accountIndex);
2108
3803
  for (const scheme of schemes) {
@@ -2111,7 +3806,7 @@ var T402WDK = class _T402WDK {
2111
3806
  } catch {
2112
3807
  }
2113
3808
  }
2114
- if (_T402WDK.isSolanaRegistered()) {
3809
+ if (this._walletModules.solana !== void 0) {
2115
3810
  try {
2116
3811
  const signer = await this.getSvmSigner(accountIndex);
2117
3812
  for (const scheme of schemes) {
@@ -2125,7 +3820,7 @@ var T402WDK = class _T402WDK {
2125
3820
  } catch {
2126
3821
  }
2127
3822
  }
2128
- if (_T402WDK.isTronRegistered()) {
3823
+ if (this._walletModules.tron !== void 0) {
2129
3824
  try {
2130
3825
  const signer = await this.getTronSigner(accountIndex);
2131
3826
  for (const scheme of schemes) {
@@ -2134,6 +3829,29 @@ var T402WDK = class _T402WDK {
2134
3829
  } catch {
2135
3830
  }
2136
3831
  }
3832
+ if (this._walletModules.spark !== void 0) {
3833
+ try {
3834
+ const signer = await this.getSparkSigner(accountIndex);
3835
+ for (const scheme of schemes) {
3836
+ entries.push({ scheme, network: "spark:mainnet", signer, family: "spark" });
3837
+ }
3838
+ } catch {
3839
+ }
3840
+ }
3841
+ if (this._walletModules.btc !== void 0) {
3842
+ try {
3843
+ const signer = await this.getBtcSigner(accountIndex);
3844
+ for (const scheme of schemes) {
3845
+ entries.push({
3846
+ scheme,
3847
+ network: "bip122:000000000019d6689c085ae165831e93",
3848
+ signer,
3849
+ family: "btc"
3850
+ });
3851
+ }
3852
+ } catch {
3853
+ }
3854
+ }
2137
3855
  return entries;
2138
3856
  }
2139
3857
  /**
@@ -2161,10 +3879,45 @@ var T402WDK = class _T402WDK {
2161
3879
  }
2162
3880
  this._seedPhrase = seedPhrase;
2163
3881
  this._balanceCache = new BalanceCache(options.cache);
3882
+ this._wdkConstructor = options.wdk ?? _T402WDK._defaultModules.wdk ?? null;
3883
+ this._walletModules = options.wallets ?? _T402WDK._defaultModules.wallets ?? {};
3884
+ this._protocolModules = options.protocols ?? _T402WDK._defaultModules.protocols ?? {};
3885
+ this._walletManagerEvm = this._walletModules.evm ?? _T402WDK._defaultModules.walletManagerEvm ?? null;
3886
+ this._bridgeUsdt0Evm = this._protocolModules.bridgeUsdt0Evm ?? _T402WDK._defaultModules.bridgeUsdt0Evm ?? null;
3887
+ this._fiatOnRampProvider = options.fiatOnRampProvider ?? _T402WDK._defaultModules.fiatOnRampProvider ?? null;
3888
+ if (options.middlewares) {
3889
+ this._middlewares = new Map(options.middlewares);
3890
+ } else if (_T402WDK._defaultModules.middlewares) {
3891
+ this._middlewares = new Map(_T402WDK._defaultModules.middlewares);
3892
+ }
3893
+ this._retryConfig = options.retry;
2164
3894
  for (const [chain, chainConfig] of Object.entries(config)) {
2165
3895
  if (chainConfig) {
2166
3896
  try {
2167
- this._normalizedChains.set(chain, normalizeChainConfig(chain, chainConfig));
3897
+ if (typeof chainConfig === "object" && "provider" in chainConfig && Array.isArray(chainConfig.provider)) {
3898
+ const urls = chainConfig.provider;
3899
+ if (urls.length === 0) {
3900
+ throw new Error("Provider array must contain at least one URL");
3901
+ }
3902
+ const failoverConfig = {
3903
+ urls,
3904
+ ...chainConfig.failover ?? {}
3905
+ };
3906
+ const failoverProvider = new FailoverProvider(failoverConfig);
3907
+ this._failoverProviders.set(chain, failoverProvider);
3908
+ const normalized = normalizeChainConfig(chain, failoverProvider.getCurrentUrl());
3909
+ if (chainConfig.chainId !== void 0) normalized.chainId = chainConfig.chainId;
3910
+ if (chainConfig.network !== void 0) normalized.network = chainConfig.network;
3911
+ this._normalizedChains.set(chain, normalized);
3912
+ } else {
3913
+ this._normalizedChains.set(
3914
+ chain,
3915
+ normalizeChainConfig(
3916
+ chain,
3917
+ chainConfig
3918
+ )
3919
+ );
3920
+ }
2168
3921
  } catch (error) {
2169
3922
  throw new ChainError(
2170
3923
  2003 /* INVALID_CHAIN_CONFIG */,
@@ -2175,10 +3928,24 @@ var T402WDK = class _T402WDK {
2175
3928
  }
2176
3929
  }
2177
3930
  this._addDefaultChainsIfNeeded();
2178
- if (!isFromWDK && _T402WDK._WDK) {
3931
+ if (!isFromWDK && this._wdkConstructor) {
2179
3932
  this._initializeWDK();
2180
3933
  }
2181
3934
  }
3935
+ /**
3936
+ * Guard: throw if this instance has been disposed (#194)
3937
+ */
3938
+ assertNotDisposed() {
3939
+ if (this._disposed) {
3940
+ throw new WDKError(1002 /* WDK_NOT_INITIALIZED */, "T402WDK has been disposed");
3941
+ }
3942
+ }
3943
+ /**
3944
+ * Whether this instance has been disposed
3945
+ */
3946
+ get isDisposed() {
3947
+ return this._disposed;
3948
+ }
2182
3949
  /**
2183
3950
  * Add default chain configurations for common chains
2184
3951
  */
@@ -2194,22 +3961,24 @@ var T402WDK = class _T402WDK {
2194
3961
  * Initialize the underlying WDK instance
2195
3962
  */
2196
3963
  _initializeWDK() {
2197
- if (!_T402WDK._WDK) {
3964
+ if (!this._wdkConstructor) {
2198
3965
  this._initializationError = new WDKInitializationError("WDK not registered");
2199
3966
  return;
2200
3967
  }
2201
- if (!_T402WDK._WalletManagerEvm) {
3968
+ if (!this._walletManagerEvm) {
2202
3969
  this._initializationError = new WDKInitializationError(
2203
3970
  "WalletManagerEvm not registered. Call T402WDK.registerWDK(WDK, WalletManagerEvm) to enable wallet functionality."
2204
3971
  );
2205
3972
  return;
2206
3973
  }
2207
3974
  try {
2208
- let wdk = new _T402WDK._WDK(this._seedPhrase);
3975
+ let wdk = new this._wdkConstructor(this._seedPhrase);
2209
3976
  for (const [chain, config] of this._normalizedChains) {
2210
3977
  try {
2211
- wdk = wdk.registerWallet(chain, _T402WDK._WalletManagerEvm, {
2212
- provider: config.provider,
3978
+ const failover = this._failoverProviders.get(chain);
3979
+ const providerUrl = failover ? failover.getCurrentUrl() : config.provider;
3980
+ wdk = wdk.registerWallet(chain, this._walletManagerEvm, {
3981
+ provider: providerUrl,
2213
3982
  chainId: config.chainId
2214
3983
  });
2215
3984
  } catch (error) {
@@ -2220,15 +3989,44 @@ var T402WDK = class _T402WDK {
2220
3989
  );
2221
3990
  }
2222
3991
  }
2223
- if (_T402WDK._BridgeUsdt0Evm) {
3992
+ if (this._bridgeUsdt0Evm) {
2224
3993
  try {
2225
- wdk = wdk.registerProtocol("bridge-usdt0", _T402WDK._BridgeUsdt0Evm);
3994
+ wdk = wdk.registerProtocol("bridge-usdt0", this._bridgeUsdt0Evm);
2226
3995
  } catch (error) {
2227
3996
  console.warn(
2228
3997
  `Failed to register USDT0 bridge protocol: ${error instanceof Error ? error.message : String(error)}`
2229
3998
  );
2230
3999
  }
2231
4000
  }
4001
+ if (this._protocolModules.swapVeloraEvm) {
4002
+ try {
4003
+ wdk = wdk.registerProtocol("swap-velora", this._protocolModules.swapVeloraEvm);
4004
+ } catch (error) {
4005
+ console.warn(
4006
+ `Failed to register Velora swap protocol: ${error instanceof Error ? error.message : String(error)}`
4007
+ );
4008
+ }
4009
+ }
4010
+ if (this._protocolModules.lendingAaveEvm) {
4011
+ try {
4012
+ wdk = wdk.registerProtocol("lending-aave", this._protocolModules.lendingAaveEvm);
4013
+ } catch (error) {
4014
+ console.warn(
4015
+ `Failed to register Aave lending protocol: ${error instanceof Error ? error.message : String(error)}`
4016
+ );
4017
+ }
4018
+ }
4019
+ if (typeof wdk.registerMiddleware === "function") {
4020
+ for (const [chain, fns] of this._middlewares) {
4021
+ for (const fn of fns) {
4022
+ try {
4023
+ ;
4024
+ wdk.registerMiddleware(chain, fn);
4025
+ } catch {
4026
+ }
4027
+ }
4028
+ }
4029
+ }
2232
4030
  this._wdk = wdk;
2233
4031
  this._initializationError = null;
2234
4032
  } catch (error) {
@@ -2267,6 +4065,47 @@ var T402WDK = class _T402WDK {
2267
4065
  get initializationError() {
2268
4066
  return this._initializationError;
2269
4067
  }
4068
+ // ========== Event Emitter ==========
4069
+ /**
4070
+ * Subscribe to a T402 event
4071
+ */
4072
+ on(event, handler) {
4073
+ this._events.on(event, handler);
4074
+ return this;
4075
+ }
4076
+ /**
4077
+ * Unsubscribe from a T402 event
4078
+ */
4079
+ off(event, handler) {
4080
+ this._events.off(event, handler);
4081
+ return this;
4082
+ }
4083
+ /**
4084
+ * Subscribe to a T402 event (fires once then auto-unsubscribes)
4085
+ */
4086
+ once(event, handler) {
4087
+ this._events.once(event, handler);
4088
+ return this;
4089
+ }
4090
+ /**
4091
+ * Emit a T402 event
4092
+ */
4093
+ emit(event, data) {
4094
+ return this._events.emit(event, data);
4095
+ }
4096
+ // ========== Receipt Store ==========
4097
+ /**
4098
+ * Get the payment receipt store
4099
+ */
4100
+ getReceiptStore() {
4101
+ return this._receiptStore;
4102
+ }
4103
+ /**
4104
+ * Set a custom payment receipt store backend
4105
+ */
4106
+ setReceiptStore(store) {
4107
+ this._receiptStore = store;
4108
+ }
2270
4109
  /**
2271
4110
  * Get all configured chains
2272
4111
  */
@@ -2295,6 +4134,7 @@ var T402WDK = class _T402WDK {
2295
4134
  * @returns An initialized WDKSigner
2296
4135
  */
2297
4136
  async getSigner(chain, accountIndex = 0) {
4137
+ this.assertNotDisposed();
2298
4138
  if (!chain || typeof chain !== "string") {
2299
4139
  throw new ChainError(
2300
4140
  2001 /* CHAIN_NOT_CONFIGURED */,
@@ -2318,7 +4158,12 @@ var T402WDK = class _T402WDK {
2318
4158
  try {
2319
4159
  const signer = await createWDKSigner(this.wdk, chain, accountIndex);
2320
4160
  this._signerCache.set(cacheKey, signer);
2321
- return signer;
4161
+ this._events.emit("signer:initialized", {
4162
+ chain,
4163
+ address: signer.address,
4164
+ family: "evm"
4165
+ });
4166
+ return signer;
2322
4167
  } catch (error) {
2323
4168
  if (isWDKError(error)) {
2324
4169
  throw error;
@@ -2337,9 +4182,69 @@ var T402WDK = class _T402WDK {
2337
4182
  */
2338
4183
  clearSignerCache() {
2339
4184
  this._signerCache.clear();
4185
+ this._pathSignerCache.clear();
2340
4186
  this._tonSignerCache.clear();
2341
4187
  this._svmSignerCache.clear();
2342
4188
  this._tronSignerCache.clear();
4189
+ this._sparkSignerCache.clear();
4190
+ this._btcSignerCache.clear();
4191
+ }
4192
+ // ========== Fee Rates & Cost Estimation ==========
4193
+ /**
4194
+ * Get current fee rates for a chain
4195
+ */
4196
+ async getFeeRates(chain) {
4197
+ if (this._wdk && typeof this._wdk.getFeeRates === "function") {
4198
+ return this._wdk.getFeeRates(chain);
4199
+ }
4200
+ return { low: 1000000000n, medium: 2000000000n, high: 5000000000n };
4201
+ }
4202
+ /**
4203
+ * Estimate total cost of a payment on a chain
4204
+ */
4205
+ async estimatePaymentCost(chain, amount) {
4206
+ const signer = await this.getSigner(chain);
4207
+ const nativeBalance = await signer.getBalance();
4208
+ let estimatedGasCost = 100000n * 2000000000n;
4209
+ try {
4210
+ const feeRates = await this.getFeeRates(chain);
4211
+ const mediumRate = feeRates.medium ?? 2000000000n;
4212
+ estimatedGasCost = 100000n * mediumRate;
4213
+ } catch {
4214
+ }
4215
+ const config = this.getChainConfig(chain);
4216
+ return {
4217
+ paymentAmount: amount,
4218
+ estimatedGasCost,
4219
+ nativeBalance,
4220
+ canAffordGas: nativeBalance >= estimatedGasCost,
4221
+ chain,
4222
+ network: config?.network ?? ""
4223
+ };
4224
+ }
4225
+ // ========== HD Derivation Paths ==========
4226
+ /**
4227
+ * Get a signer using a custom BIP-44 derivation path
4228
+ */
4229
+ async getSignerByPath(chain, path) {
4230
+ const cacheKey = `${chain}:path:${path}`;
4231
+ const cached = this._pathSignerCache.get(cacheKey);
4232
+ if (cached) return cached;
4233
+ if (!this._wdk) {
4234
+ throw new WDKInitializationError("WDK not initialized");
4235
+ }
4236
+ if (typeof this._wdk.getAccountByPath !== "function") {
4237
+ throw new Error(
4238
+ "getAccountByPath not available. Upgrade @tetherto/wdk to support custom derivation paths."
4239
+ );
4240
+ }
4241
+ const account = await this._wdk.getAccountByPath(chain, path);
4242
+ const address = await account.getAddress();
4243
+ const signer = new WDKSigner(this._wdk, chain, 0);
4244
+ signer._account = account;
4245
+ signer._address = address;
4246
+ this._pathSignerCache.set(cacheKey, signer);
4247
+ return signer;
2343
4248
  }
2344
4249
  // ========== Multi-Chain Signers ==========
2345
4250
  /**
@@ -2359,11 +4264,12 @@ var T402WDK = class _T402WDK {
2359
4264
  * ```
2360
4265
  */
2361
4266
  async getTonSigner(accountIndex = 0) {
4267
+ this.assertNotDisposed();
2362
4268
  const cached = this._tonSignerCache.get(accountIndex);
2363
4269
  if (cached) {
2364
4270
  return cached;
2365
4271
  }
2366
- if (!_T402WDK._WalletModules.ton) {
4272
+ if (!this._walletModules.ton) {
2367
4273
  throw new ChainError(
2368
4274
  2002 /* CHAIN_NOT_SUPPORTED */,
2369
4275
  "TON wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { ton: WalletManagerTon } }).",
@@ -2374,6 +4280,11 @@ var T402WDK = class _T402WDK {
2374
4280
  const account = await this.wdk.getAccount("ton", accountIndex);
2375
4281
  const signer = await createWDKTonSigner(account);
2376
4282
  this._tonSignerCache.set(accountIndex, signer);
4283
+ this._events.emit("signer:initialized", {
4284
+ chain: "ton",
4285
+ address: signer.address.toString(),
4286
+ family: "ton"
4287
+ });
2377
4288
  return signer;
2378
4289
  } catch (error) {
2379
4290
  if (isWDKError(error)) {
@@ -2402,11 +4313,12 @@ var T402WDK = class _T402WDK {
2402
4313
  * ```
2403
4314
  */
2404
4315
  async getSvmSigner(accountIndex = 0) {
4316
+ this.assertNotDisposed();
2405
4317
  const cached = this._svmSignerCache.get(accountIndex);
2406
4318
  if (cached) {
2407
4319
  return cached;
2408
4320
  }
2409
- if (!_T402WDK._WalletModules.solana) {
4321
+ if (!this._walletModules.solana) {
2410
4322
  throw new ChainError(
2411
4323
  2002 /* CHAIN_NOT_SUPPORTED */,
2412
4324
  "Solana wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { solana: WalletManagerSolana } }).",
@@ -2420,6 +4332,11 @@ var T402WDK = class _T402WDK {
2420
4332
  );
2421
4333
  const signer = await createWDKSvmSigner(account);
2422
4334
  this._svmSignerCache.set(accountIndex, signer);
4335
+ this._events.emit("signer:initialized", {
4336
+ chain: "solana",
4337
+ address: signer.address.toString(),
4338
+ family: "svm"
4339
+ });
2423
4340
  return signer;
2424
4341
  } catch (error) {
2425
4342
  if (isWDKError(error)) {
@@ -2451,13 +4368,14 @@ var T402WDK = class _T402WDK {
2451
4368
  * ```
2452
4369
  */
2453
4370
  async getTronSigner(accountIndex = 0, rpcUrl) {
4371
+ this.assertNotDisposed();
2454
4372
  if (!rpcUrl) {
2455
4373
  const cached = this._tronSignerCache.get(accountIndex);
2456
4374
  if (cached) {
2457
4375
  return cached;
2458
4376
  }
2459
4377
  }
2460
- if (!_T402WDK._WalletModules.tron) {
4378
+ if (!this._walletModules.tron) {
2461
4379
  throw new ChainError(
2462
4380
  2002 /* CHAIN_NOT_SUPPORTED */,
2463
4381
  "TRON wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { tron: WalletManagerTron } }).",
@@ -2470,6 +4388,11 @@ var T402WDK = class _T402WDK {
2470
4388
  if (!rpcUrl) {
2471
4389
  this._tronSignerCache.set(accountIndex, signer);
2472
4390
  }
4391
+ this._events.emit("signer:initialized", {
4392
+ chain: "tron",
4393
+ address: signer.address,
4394
+ family: "tron"
4395
+ });
2473
4396
  return signer;
2474
4397
  } catch (error) {
2475
4398
  if (isWDKError(error)) {
@@ -2481,6 +4404,109 @@ var T402WDK = class _T402WDK {
2481
4404
  });
2482
4405
  }
2483
4406
  }
4407
+ /**
4408
+ * Get a Spark (Bitcoin L2) signer for T402 payments
4409
+ *
4410
+ * @param accountIndex - HD wallet account index (default: 0)
4411
+ * @throws {ChainError} If Spark wallet manager is not registered
4412
+ * @returns An initialized WDKSparkSignerAdapter
4413
+ *
4414
+ * @example
4415
+ * ```typescript
4416
+ * const sparkSigner = await wallet.getSparkSigner();
4417
+ *
4418
+ * const client = createT402HTTPClient({
4419
+ * signers: [{ scheme: 'exact', network: 'spark:mainnet', signer: sparkSigner }]
4420
+ * });
4421
+ * ```
4422
+ */
4423
+ async getSparkSigner(accountIndex = 0) {
4424
+ this.assertNotDisposed();
4425
+ const cached = this._sparkSignerCache.get(accountIndex);
4426
+ if (cached) {
4427
+ return cached;
4428
+ }
4429
+ if (!this._walletModules.spark) {
4430
+ throw new ChainError(
4431
+ 2002 /* CHAIN_NOT_SUPPORTED */,
4432
+ "Spark wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { spark: SparkWalletManager } }).",
4433
+ { chain: "spark" }
4434
+ );
4435
+ }
4436
+ try {
4437
+ const account = await this.wdk.getAccount(
4438
+ "spark",
4439
+ accountIndex
4440
+ );
4441
+ const signer = await createWDKSparkSigner(account);
4442
+ this._sparkSignerCache.set(accountIndex, signer);
4443
+ this._events.emit("signer:initialized", {
4444
+ chain: "spark",
4445
+ address: signer.address,
4446
+ family: "spark"
4447
+ });
4448
+ return signer;
4449
+ } catch (error) {
4450
+ if (isWDKError(error)) {
4451
+ throw error;
4452
+ }
4453
+ throw wrapError(error, 3001 /* SIGNER_NOT_INITIALIZED */, "Failed to create Spark signer", {
4454
+ chain: "spark",
4455
+ accountIndex
4456
+ });
4457
+ }
4458
+ }
4459
+ /**
4460
+ * Get a Bitcoin (BTC) on-chain signer for T402 payments
4461
+ *
4462
+ * @param accountIndex - HD wallet account index (default: 0)
4463
+ * @throws {ChainError} If Bitcoin wallet manager is not registered
4464
+ * @returns An initialized WDKBtcSignerAdapter
4465
+ *
4466
+ * @example
4467
+ * ```typescript
4468
+ * const btcSigner = await wallet.getBtcSigner();
4469
+ *
4470
+ * const client = createT402HTTPClient({
4471
+ * signers: [{ scheme: 'exact', network: 'bip122:000000000019d6689c085ae165831e93', signer: btcSigner }]
4472
+ * });
4473
+ * ```
4474
+ */
4475
+ async getBtcSigner(accountIndex = 0) {
4476
+ this.assertNotDisposed();
4477
+ const cached = this._btcSignerCache.get(accountIndex);
4478
+ if (cached) {
4479
+ return cached;
4480
+ }
4481
+ if (!this._walletModules.btc) {
4482
+ throw new ChainError(
4483
+ 2002 /* CHAIN_NOT_SUPPORTED */,
4484
+ "Bitcoin wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { btc: WalletManagerBtc } }).",
4485
+ { chain: "btc" }
4486
+ );
4487
+ }
4488
+ try {
4489
+ const account = await this.wdk.getAccount("btc", accountIndex);
4490
+ const signer = await createWDKBtcSigner(account);
4491
+ this._btcSignerCache.set(accountIndex, signer);
4492
+ this._events.emit("signer:initialized", {
4493
+ chain: "btc",
4494
+ address: signer.address,
4495
+ family: "btc"
4496
+ });
4497
+ return signer;
4498
+ } catch (error) {
4499
+ if (isWDKError(error)) {
4500
+ throw error;
4501
+ }
4502
+ throw wrapError(
4503
+ error,
4504
+ 3001 /* SIGNER_NOT_INITIALIZED */,
4505
+ "Failed to create Bitcoin signer",
4506
+ { chain: "btc", accountIndex }
4507
+ );
4508
+ }
4509
+ }
2484
4510
  /**
2485
4511
  * Get a signer for a specific chain family
2486
4512
  *
@@ -2519,10 +4545,14 @@ var T402WDK = class _T402WDK {
2519
4545
  return this.getSvmSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
2520
4546
  case "tron":
2521
4547
  return this.getTronSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
4548
+ case "spark":
4549
+ return this.getSparkSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
4550
+ case "btc":
4551
+ return this.getBtcSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
2522
4552
  default:
2523
4553
  throw new ChainError(
2524
4554
  2002 /* CHAIN_NOT_SUPPORTED */,
2525
- `Chain family "${family}" is not supported. Available: evm, ton, svm, tron`,
4555
+ `Chain family "${family}" is not supported. Available: evm, ton, svm, tron, spark, btc`,
2526
4556
  { chain: family }
2527
4557
  );
2528
4558
  }
@@ -2536,6 +4566,7 @@ var T402WDK = class _T402WDK {
2536
4566
  * @throws {SignerError} If address fetch fails
2537
4567
  */
2538
4568
  async getAddress(chain, accountIndex = 0) {
4569
+ this.assertNotDisposed();
2539
4570
  const signer = await this.getSigner(chain, accountIndex);
2540
4571
  return signer.address;
2541
4572
  }
@@ -2547,6 +4578,7 @@ var T402WDK = class _T402WDK {
2547
4578
  * @throws {BalanceError} If balance fetch fails
2548
4579
  */
2549
4580
  async getUsdt0Balance(chain, accountIndex = 0) {
4581
+ this.assertNotDisposed();
2550
4582
  const usdt0Address = USDT0_ADDRESSES[chain];
2551
4583
  if (!usdt0Address) {
2552
4584
  return 0n;
@@ -2558,7 +4590,7 @@ var T402WDK = class _T402WDK {
2558
4590
  chain,
2559
4591
  usdt0Address,
2560
4592
  address,
2561
- async () => signer.getTokenBalance(usdt0Address)
4593
+ () => this._withRetry(() => signer.getTokenBalance(usdt0Address))
2562
4594
  );
2563
4595
  } catch (error) {
2564
4596
  if (isWDKError(error) && error.code === 5002 /* TOKEN_BALANCE_FETCH_FAILED */) {
@@ -2575,6 +4607,7 @@ var T402WDK = class _T402WDK {
2575
4607
  * @throws {BalanceError} If balance fetch fails
2576
4608
  */
2577
4609
  async getUsdcBalance(chain, accountIndex = 0) {
4610
+ this.assertNotDisposed();
2578
4611
  const usdcAddress = USDC_ADDRESSES[chain];
2579
4612
  if (!usdcAddress) {
2580
4613
  return 0n;
@@ -2586,7 +4619,7 @@ var T402WDK = class _T402WDK {
2586
4619
  chain,
2587
4620
  usdcAddress,
2588
4621
  address,
2589
- async () => signer.getTokenBalance(usdcAddress)
4622
+ () => this._withRetry(() => signer.getTokenBalance(usdcAddress))
2590
4623
  );
2591
4624
  } catch (error) {
2592
4625
  if (isWDKError(error) && error.code === 5002 /* TOKEN_BALANCE_FETCH_FAILED */) {
@@ -2604,6 +4637,7 @@ var T402WDK = class _T402WDK {
2604
4637
  * @throws {BalanceError} If balance fetch fails
2605
4638
  */
2606
4639
  async getChainBalances(chain, accountIndex = 0) {
4640
+ this.assertNotDisposed();
2607
4641
  const config = this._normalizedChains.get(chain);
2608
4642
  if (!config) {
2609
4643
  throw new ChainError(2001 /* CHAIN_NOT_CONFIGURED */, `Chain "${chain}" not configured`, {
@@ -2620,7 +4654,7 @@ var T402WDK = class _T402WDK {
2620
4654
  chain,
2621
4655
  token.address,
2622
4656
  address,
2623
- async () => signer.getTokenBalance(token.address)
4657
+ () => this._withRetry(() => signer.getTokenBalance(token.address))
2624
4658
  );
2625
4659
  return {
2626
4660
  token: token.address,
@@ -2649,7 +4683,7 @@ var T402WDK = class _T402WDK {
2649
4683
  nativeBalance = await this._balanceCache.getOrFetchNativeBalance(
2650
4684
  chain,
2651
4685
  address,
2652
- async () => signer.getBalance()
4686
+ () => this._withRetry(() => signer.getBalance())
2653
4687
  );
2654
4688
  } catch {
2655
4689
  nativeBalance = 0n;
@@ -2742,6 +4776,16 @@ var T402WDK = class _T402WDK {
2742
4776
  for (const chainBalance of balances.chains) {
2743
4777
  const tokenBalance = chainBalance.tokens.find((t) => t.symbol === tokenSymbol);
2744
4778
  if (tokenBalance && tokenBalance.balance >= amount) {
4779
+ try {
4780
+ const costEstimate = await this.estimatePaymentCost(
4781
+ chainBalance.chain,
4782
+ amount.toString()
4783
+ );
4784
+ if (!costEstimate.canAffordGas) {
4785
+ continue;
4786
+ }
4787
+ } catch {
4788
+ }
2745
4789
  return {
2746
4790
  chain: chainBalance.chain,
2747
4791
  token: tokenSymbol,
@@ -2775,7 +4819,8 @@ var T402WDK = class _T402WDK {
2775
4819
  * @returns Bridge result with transaction hash
2776
4820
  */
2777
4821
  async bridgeUsdt0(params) {
2778
- if (!_T402WDK._BridgeUsdt0Evm) {
4822
+ this.assertNotDisposed();
4823
+ if (!this._bridgeUsdt0Evm) {
2779
4824
  throw new BridgeError(
2780
4825
  7001 /* BRIDGE_NOT_AVAILABLE */,
2781
4826
  "USDT0 bridge not available. Register BridgeUsdt0Evm with T402WDK.registerWDK().",
@@ -2810,6 +4855,11 @@ var T402WDK = class _T402WDK {
2810
4855
  }
2811
4856
  try {
2812
4857
  const recipient = params.recipient ?? await this.getAddress(params.toChain);
4858
+ this._events.emit("bridge:start", {
4859
+ fromChain: params.fromChain,
4860
+ toChain: params.toChain,
4861
+ amount: params.amount
4862
+ });
2813
4863
  const result = await this.wdk.executeProtocol("bridge-usdt0", {
2814
4864
  fromChain: params.fromChain,
2815
4865
  toChain: params.toChain,
@@ -2823,6 +4873,11 @@ var T402WDK = class _T402WDK {
2823
4873
  { fromChain: params.fromChain, toChain: params.toChain }
2824
4874
  );
2825
4875
  }
4876
+ this._events.emit("bridge:confirmed", {
4877
+ txHash: result.txHash,
4878
+ fromChain: params.fromChain,
4879
+ toChain: params.toChain
4880
+ });
2826
4881
  return {
2827
4882
  txHash: result.txHash,
2828
4883
  estimatedTime: 300
@@ -2878,7 +4933,7 @@ var T402WDK = class _T402WDK {
2878
4933
  * Check if the Velora swap protocol is registered and available
2879
4934
  */
2880
4935
  canSwap() {
2881
- return _T402WDK._ProtocolModules.swapVeloraEvm !== void 0;
4936
+ return this._protocolModules.swapVeloraEvm !== void 0;
2882
4937
  }
2883
4938
  /**
2884
4939
  * Get a swap quote for converting a token to USDT0
@@ -2985,6 +5040,131 @@ var T402WDK = class _T402WDK {
2985
5040
  );
2986
5041
  }
2987
5042
  }
5043
+ // ========== Lending Protocol ==========
5044
+ /**
5045
+ * Check if the Aave lending protocol is registered and available
5046
+ */
5047
+ canBorrow() {
5048
+ return this._protocolModules.lendingAaveEvm !== void 0;
5049
+ }
5050
+ /**
5051
+ * Borrow USDT0 against collateral and pay
5052
+ *
5053
+ * Uses the Aave protocol to deposit collateral, borrow USDT0, then the
5054
+ * borrowed USDT0 is available for T402 payments.
5055
+ *
5056
+ * @param params - Borrow parameters
5057
+ * @throws {WDKError} If lending protocol is not registered or borrow fails
5058
+ *
5059
+ * @example
5060
+ * ```typescript
5061
+ * // Borrow 100 USDT0 against 0.05 WETH on Arbitrum
5062
+ * const result = await wallet.borrowAndPay({
5063
+ * chain: 'arbitrum',
5064
+ * collateralToken: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', // WETH
5065
+ * collateralAmount: 50000000000000000n, // 0.05 WETH
5066
+ * borrowAmount: 100000000n, // 100 USDT0
5067
+ * });
5068
+ * ```
5069
+ */
5070
+ async borrowAndPay(params) {
5071
+ if (!this.canBorrow()) {
5072
+ throw new WDKError(
5073
+ 8101 /* PROTOCOL_NOT_REGISTERED */,
5074
+ "Aave lending protocol not registered. Call T402WDK.registerWDK(WDK, { protocols: { lendingAaveEvm: LendingAaveEvm } })."
5075
+ );
5076
+ }
5077
+ const usdt0Address = USDT0_ADDRESSES[params.chain];
5078
+ if (!usdt0Address) {
5079
+ throw new ChainError(
5080
+ 2002 /* CHAIN_NOT_SUPPORTED */,
5081
+ `Chain "${params.chain}" does not have a known USDT0 address`,
5082
+ { chain: params.chain }
5083
+ );
5084
+ }
5085
+ if (params.collateralAmount <= 0n) {
5086
+ throw new WDKError(8103 /* INVALID_PARAMETER */, "collateralAmount must be greater than 0");
5087
+ }
5088
+ if (params.borrowAmount <= 0n) {
5089
+ throw new WDKError(8103 /* INVALID_PARAMETER */, "borrowAmount must be greater than 0");
5090
+ }
5091
+ try {
5092
+ const result = await this.wdk.executeProtocol("lending-aave", {
5093
+ action: "borrow",
5094
+ chain: params.chain,
5095
+ collateralToken: params.collateralToken,
5096
+ collateralAmount: params.collateralAmount.toString(),
5097
+ borrowToken: usdt0Address,
5098
+ borrowAmount: params.borrowAmount.toString(),
5099
+ interestRateMode: params.interestRateMode ?? 2
5100
+ });
5101
+ this._balanceCache.invalidateChain(params.chain);
5102
+ const r = result;
5103
+ return {
5104
+ supplyTxHash: r.supplyTxHash,
5105
+ borrowTxHash: r.borrowTxHash,
5106
+ borrowedAmount: BigInt(r.borrowedAmount)
5107
+ };
5108
+ } catch (error) {
5109
+ throw wrapError(
5110
+ error,
5111
+ 8102 /* PROTOCOL_EXECUTION_FAILED */,
5112
+ `Failed to execute borrow on ${params.chain}`,
5113
+ {
5114
+ chain: params.chain,
5115
+ collateralToken: params.collateralToken,
5116
+ borrowAmount: params.borrowAmount.toString()
5117
+ }
5118
+ );
5119
+ }
5120
+ }
5121
+ // ========== Fiat On-Ramp ==========
5122
+ /**
5123
+ * Get a fiat on-ramp quote
5124
+ *
5125
+ * @param params - Quote parameters (fiatAmount, fiatCurrency, network)
5126
+ * @throws {WDKError} If no fiat on-ramp provider is registered
5127
+ */
5128
+ async getFiatOnRampQuote(params) {
5129
+ this.assertNotDisposed();
5130
+ if (!this._fiatOnRampProvider) {
5131
+ throw new WDKError(
5132
+ 8101 /* PROTOCOL_NOT_REGISTERED */,
5133
+ "No fiat on-ramp provider registered. Call T402WDK.registerFiatOnRamp() first."
5134
+ );
5135
+ }
5136
+ return this._fiatOnRampProvider.getQuote(params);
5137
+ }
5138
+ /**
5139
+ * Generate a fiat on-ramp widget URL for the user
5140
+ *
5141
+ * Returns a widget URL that the application should open in a browser
5142
+ * or webview so the user can complete the fiat purchase.
5143
+ *
5144
+ * @param params - On-ramp parameters
5145
+ * @throws {WDKError} If no fiat on-ramp provider is registered
5146
+ *
5147
+ * @example
5148
+ * ```typescript
5149
+ * const result = await wallet.onRampAndPay({
5150
+ * fiatAmount: 100,
5151
+ * fiatCurrency: 'USD',
5152
+ * walletAddress: '0x...',
5153
+ * network: 'eip155:42161',
5154
+ * });
5155
+ * // Open result.widgetUrl in browser/webview
5156
+ * ```
5157
+ */
5158
+ onRampAndPay(params) {
5159
+ this.assertNotDisposed();
5160
+ if (!this._fiatOnRampProvider) {
5161
+ throw new WDKError(
5162
+ 8101 /* PROTOCOL_NOT_REGISTERED */,
5163
+ "No fiat on-ramp provider registered. Call T402WDK.registerFiatOnRamp() first."
5164
+ );
5165
+ }
5166
+ return this._fiatOnRampProvider.createWidget(params);
5167
+ }
2988
5168
  // ========== Cache Management ==========
2989
5169
  /**
2990
5170
  * Check if balance caching is enabled
@@ -3011,6 +5191,14 @@ var T402WDK = class _T402WDK {
3011
5191
  */
3012
5192
  invalidateBalanceCache() {
3013
5193
  this._balanceCache.clear();
5194
+ for (const chain of this.getConfiguredChains()) {
5195
+ this._events.emit("balance:changed", {
5196
+ chain,
5197
+ token: "*",
5198
+ previousBalance: 0n,
5199
+ newBalance: 0n
5200
+ });
5201
+ }
3014
5202
  }
3015
5203
  /**
3016
5204
  * Invalidate cached balances for a specific chain
@@ -3019,7 +5207,16 @@ var T402WDK = class _T402WDK {
3019
5207
  * @returns Number of cache entries invalidated
3020
5208
  */
3021
5209
  invalidateChainCache(chain) {
3022
- return this._balanceCache.invalidateChain(chain);
5210
+ const count = this._balanceCache.invalidateChain(chain);
5211
+ if (count > 0) {
5212
+ this._events.emit("balance:changed", {
5213
+ chain,
5214
+ token: "*",
5215
+ previousBalance: 0n,
5216
+ newBalance: 0n
5217
+ });
5218
+ }
5219
+ return count;
3023
5220
  }
3024
5221
  /**
3025
5222
  * Invalidate cached balances for a specific address
@@ -3031,16 +5228,92 @@ var T402WDK = class _T402WDK {
3031
5228
  return this._balanceCache.invalidateAddress(address);
3032
5229
  }
3033
5230
  /**
3034
- * Dispose of cache resources
5231
+ * Dispose of all resources held by this instance (#194).
3035
5232
  *
3036
- * Call this when the T402WDK instance is no longer needed.
5233
+ * After disposal, any public method call will throw.
5234
+ * Safe to call multiple times.
3037
5235
  */
3038
5236
  dispose() {
3039
- this._balanceCache.dispose();
5237
+ if (this._disposed) return;
5238
+ this._disposed = true;
5239
+ if (this._wdk && typeof this._wdk.dispose === "function") {
5240
+ try {
5241
+ ;
5242
+ this._wdk.dispose();
5243
+ } catch {
5244
+ }
5245
+ }
5246
+ this._wdk = null;
3040
5247
  this._signerCache.clear();
5248
+ this._pathSignerCache.clear();
3041
5249
  this._tonSignerCache.clear();
3042
5250
  this._svmSignerCache.clear();
3043
5251
  this._tronSignerCache.clear();
5252
+ this._sparkSignerCache.clear();
5253
+ this._btcSignerCache.clear();
5254
+ this._seedPhrase = "";
5255
+ this._balanceCache.dispose();
5256
+ for (const provider of this._failoverProviders.values()) {
5257
+ provider.dispose();
5258
+ }
5259
+ this._failoverProviders.clear();
5260
+ }
5261
+ /**
5262
+ * Symbol.dispose support for `using` declarations (TC39 Explicit Resource Management)
5263
+ */
5264
+ [Symbol.dispose]() {
5265
+ this.dispose();
5266
+ }
5267
+ // ========== Failover Provider Status (#195) ==========
5268
+ /**
5269
+ * Get the FailoverProvider status for a chain, if one exists.
5270
+ *
5271
+ * @param chain - Chain name
5272
+ * @returns Array of provider statuses, or null if no failover is configured for the chain
5273
+ */
5274
+ getProviderStatus(chain) {
5275
+ const provider = this._failoverProviders.get(chain);
5276
+ if (!provider) return null;
5277
+ return provider.getStatus();
5278
+ }
5279
+ // ========== Network Resilience (#202) ==========
5280
+ /**
5281
+ * Simple online connectivity check.
5282
+ * Returns true if at least one configured chain's RPC responds.
5283
+ */
5284
+ get isOnline() {
5285
+ return this._checkOnline();
5286
+ }
5287
+ async _checkOnline() {
5288
+ const chains = this.getConfiguredChains();
5289
+ if (chains.length === 0) return false;
5290
+ for (const chain of chains) {
5291
+ const config = this._normalizedChains.get(chain);
5292
+ if (!config) continue;
5293
+ try {
5294
+ const controller = new AbortController();
5295
+ const timeout = setTimeout(() => controller.abort(), 3e3);
5296
+ const response = await fetch(config.provider, {
5297
+ method: "POST",
5298
+ headers: { "Content-Type": "application/json" },
5299
+ body: JSON.stringify({ jsonrpc: "2.0", method: "eth_chainId", params: [], id: 1 }),
5300
+ signal: controller.signal
5301
+ });
5302
+ clearTimeout(timeout);
5303
+ if (response.ok) return true;
5304
+ } catch {
5305
+ }
5306
+ }
5307
+ return false;
5308
+ }
5309
+ /**
5310
+ * Wrap an async operation with the instance retry config (#202)
5311
+ */
5312
+ async _withRetry(fn) {
5313
+ if (this._retryConfig) {
5314
+ return withRetry(fn, this._retryConfig);
5315
+ }
5316
+ return fn();
3044
5317
  }
3045
5318
  };
3046
5319
  function formatTokenAmount(amount, decimals) {
@@ -3058,158 +5331,1136 @@ function formatTokenAmount(amount, decimals) {
3058
5331
  return `${whole}.${trimmed}`;
3059
5332
  }
3060
5333
 
3061
- // src/bridge.ts
3062
- var import_evm2 = require("@t402/evm");
3063
- var WdkBridge = class {
3064
- bridges = /* @__PURE__ */ new Map();
3065
- /**
3066
- * Create bridge signer adapter from WDK signer
3067
- */
3068
- createBridgeSigner(signer) {
5334
+ // src/validation.ts
5335
+ var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
5336
+ var TON_RAW_RE = /^0:[0-9a-fA-F]{64}$/;
5337
+ var TRON_ADDRESS_RE = /^T[1-9A-HJ-NP-Za-km-z]{33}$/;
5338
+ var BASE58_CHARS = /^[1-9A-HJ-NP-Za-km-z]+$/;
5339
+ var BECH32_BTC_RE = /^bc1[a-zA-HJ-NP-Z0-9]{25,90}$/;
5340
+ var COSMOS_BECH32_RE = /^[a-z]+1[a-z0-9]{38,58}$/;
5341
+ function isBase58(s) {
5342
+ return BASE58_CHARS.test(s);
5343
+ }
5344
+ function validateEvm(address) {
5345
+ if (!EVM_ADDRESS_RE.test(address)) {
5346
+ const detected = detectFamily(address, "evm");
5347
+ if (detected) {
5348
+ return {
5349
+ valid: false,
5350
+ error: `Address appears to be a ${detected} address, not an EVM address`,
5351
+ detectedFamily: detected
5352
+ };
5353
+ }
3069
5354
  return {
3070
- address: signer.address,
3071
- readContract: async (_args) => {
3072
- throw new Error(
3073
- "readContract not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
3074
- );
3075
- },
3076
- writeContract: async (_args) => {
3077
- throw new Error(
3078
- "writeContract not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
3079
- );
3080
- },
3081
- waitForTransactionReceipt: async (_args) => {
3082
- throw new Error(
3083
- "waitForTransactionReceipt not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
3084
- );
3085
- }
5355
+ valid: false,
5356
+ error: "Invalid EVM address: must be 0x-prefixed, 40 hex characters"
3086
5357
  };
3087
5358
  }
3088
- /**
3089
- * Get or create a bridge instance for a chain
3090
- */
3091
- getBridge(chain, signer) {
3092
- const cached = this.bridges.get(chain);
3093
- if (cached) {
3094
- return cached;
5359
+ return {
5360
+ valid: true,
5361
+ normalized: address.toLowerCase()
5362
+ };
5363
+ }
5364
+ function validateTon(address) {
5365
+ if (TON_RAW_RE.test(address)) {
5366
+ return { valid: true, normalized: address.toLowerCase() };
5367
+ }
5368
+ const base64UrlRe = /^[A-Za-z0-9_\-+/=]{44,48}$/;
5369
+ if (base64UrlRe.test(address)) {
5370
+ return { valid: true, normalized: address };
5371
+ }
5372
+ const detected = detectFamily(address, "ton");
5373
+ if (detected) {
5374
+ return {
5375
+ valid: false,
5376
+ error: `Address appears to be a ${detected} address, not a TON address`,
5377
+ detectedFamily: detected
5378
+ };
5379
+ }
5380
+ return {
5381
+ valid: false,
5382
+ error: "Invalid TON address: must be raw format (0:<64 hex>) or user-friendly (48 chars base64)"
5383
+ };
5384
+ }
5385
+ function validateTron(address) {
5386
+ if (!TRON_ADDRESS_RE.test(address)) {
5387
+ const detected = detectFamily(address, "tron");
5388
+ if (detected) {
5389
+ return {
5390
+ valid: false,
5391
+ error: `Address appears to be a ${detected} address, not a TRON address`,
5392
+ detectedFamily: detected
5393
+ };
3095
5394
  }
3096
- const bridgeSigner = this.createBridgeSigner(signer);
3097
- const bridge = new import_evm2.Usdt0Bridge(bridgeSigner, chain);
3098
- this.bridges.set(chain, bridge);
3099
- return bridge;
5395
+ return {
5396
+ valid: false,
5397
+ error: "Invalid TRON address: must be T-prefixed base58check, 34 characters"
5398
+ };
5399
+ }
5400
+ return { valid: true, normalized: address };
5401
+ }
5402
+ function validateSvm(address) {
5403
+ if (TRON_ADDRESS_RE.test(address)) {
5404
+ return {
5405
+ valid: false,
5406
+ error: "Address appears to be a tron address, not a Solana address",
5407
+ detectedFamily: "tron"
5408
+ };
5409
+ }
5410
+ if (!isBase58(address) || address.length < 32 || address.length > 44) {
5411
+ const detected = detectFamily(address, "svm");
5412
+ if (detected) {
5413
+ return {
5414
+ valid: false,
5415
+ error: `Address appears to be a ${detected} address, not a Solana address`,
5416
+ detectedFamily: detected
5417
+ };
5418
+ }
5419
+ return {
5420
+ valid: false,
5421
+ error: "Invalid Solana address: must be base58, 32-44 characters"
5422
+ };
5423
+ }
5424
+ return { valid: true, normalized: address };
5425
+ }
5426
+ function validateBtc(address) {
5427
+ if (BECH32_BTC_RE.test(address)) {
5428
+ return { valid: true, normalized: address.toLowerCase() };
5429
+ }
5430
+ if ((address.startsWith("1") || address.startsWith("3")) && isBase58(address)) {
5431
+ if (address.length >= 25 && address.length <= 34) {
5432
+ return { valid: true, normalized: address };
5433
+ }
5434
+ }
5435
+ const detected = detectFamily(address, "btc");
5436
+ if (detected) {
5437
+ return {
5438
+ valid: false,
5439
+ error: `Address appears to be a ${detected} address, not a Bitcoin address`,
5440
+ detectedFamily: detected
5441
+ };
5442
+ }
5443
+ return {
5444
+ valid: false,
5445
+ error: "Invalid Bitcoin address: must be bech32 (bc1...) or base58 (1... or 3...), 25-90 characters"
5446
+ };
5447
+ }
5448
+ function validateCosmos(address) {
5449
+ if (!COSMOS_BECH32_RE.test(address)) {
5450
+ const detected = detectFamily(address, "cosmos");
5451
+ if (detected) {
5452
+ return {
5453
+ valid: false,
5454
+ error: `Address appears to be a ${detected} address, not a Cosmos address`,
5455
+ detectedFamily: detected
5456
+ };
5457
+ }
5458
+ return {
5459
+ valid: false,
5460
+ error: "Invalid Cosmos address: must be bech32 with lowercase prefix"
5461
+ };
5462
+ }
5463
+ return { valid: true, normalized: address };
5464
+ }
5465
+ function detectFamily(address, exclude) {
5466
+ if (exclude !== "evm" && EVM_ADDRESS_RE.test(address)) return "evm";
5467
+ if (exclude !== "tron" && TRON_ADDRESS_RE.test(address)) return "tron";
5468
+ if (exclude !== "ton" && (TON_RAW_RE.test(address) || /^[A-Za-z0-9_\-+/=]{44,48}$/.test(address)))
5469
+ return "ton";
5470
+ if (exclude !== "btc" && (BECH32_BTC_RE.test(address) || address.startsWith("1") && isBase58(address) && address.length >= 25 && address.length <= 34))
5471
+ return "btc";
5472
+ if (exclude !== "svm" && exclude !== "tron" && isBase58(address) && address.length >= 32 && address.length <= 44 && !address.startsWith("T"))
5473
+ return "svm";
5474
+ return void 0;
5475
+ }
5476
+ var VALIDATORS = {
5477
+ evm: validateEvm,
5478
+ ton: validateTon,
5479
+ tron: validateTron,
5480
+ svm: validateSvm,
5481
+ btc: validateBtc,
5482
+ spark: validateBtc,
5483
+ // Spark uses Bitcoin addresses
5484
+ cosmos: validateCosmos
5485
+ };
5486
+ function validatePaymentAddress(address, family) {
5487
+ if (!address || typeof address !== "string") {
5488
+ return { valid: false, error: "Address is required" };
5489
+ }
5490
+ const trimmed = address.trim();
5491
+ if (trimmed.length === 0) {
5492
+ return { valid: false, error: "Address is required" };
5493
+ }
5494
+ const validator = VALIDATORS[family];
5495
+ if (!validator) {
5496
+ return { valid: false, error: `Unsupported chain family: ${family}` };
5497
+ }
5498
+ return validator(trimmed);
5499
+ }
5500
+
5501
+ // src/bridge.ts
5502
+ var import_evm2 = require("@t402/evm");
5503
+
5504
+ // src/bridge-tracker.ts
5505
+ var LAYERZERO_SCAN_API = "https://scan.layerzero-api.com/v1";
5506
+ var BridgeTracker = class {
5507
+ apiBaseUrl;
5508
+ constructor(config) {
5509
+ this.apiBaseUrl = config?.apiBaseUrl ?? LAYERZERO_SCAN_API;
5510
+ }
5511
+ /** Get current status of a bridge message */
5512
+ async getStatus(txHash) {
5513
+ const response = await fetch(`${this.apiBaseUrl}/messages/tx/${txHash}`);
5514
+ if (!response.ok) {
5515
+ if (response.status === 404) return { status: "INFLIGHT" };
5516
+ throw new Error(`LayerZero API error: ${response.status}`);
5517
+ }
5518
+ const data = await response.json();
5519
+ return mapLayerZeroStatus(data);
5520
+ }
5521
+ /** Wait for delivery with polling */
5522
+ async waitForDelivery(txHash, options) {
5523
+ const timeout = options?.timeout ?? 6e5;
5524
+ const pollInterval = options?.pollInterval ?? 1e4;
5525
+ const startTime = Date.now();
5526
+ while (Date.now() - startTime < timeout) {
5527
+ const { status, dstTxHash } = await this.getStatus(txHash);
5528
+ options?.onStatusChange?.(status);
5529
+ if (status === "DELIVERED") {
5530
+ return {
5531
+ success: true,
5532
+ status,
5533
+ dstTxHash,
5534
+ srcTxHash: txHash,
5535
+ messageGuid: txHash
5536
+ };
5537
+ }
5538
+ if (status === "FAILED" || status === "BLOCKED") {
5539
+ return {
5540
+ success: false,
5541
+ status,
5542
+ srcTxHash: txHash,
5543
+ messageGuid: txHash,
5544
+ error: `Bridge ${status.toLowerCase()}`
5545
+ };
5546
+ }
5547
+ await new Promise((r) => setTimeout(r, pollInterval));
5548
+ }
5549
+ return {
5550
+ success: false,
5551
+ status: "INFLIGHT",
5552
+ srcTxHash: txHash,
5553
+ messageGuid: txHash,
5554
+ error: "Timeout waiting for delivery"
5555
+ };
5556
+ }
5557
+ };
5558
+ function mapLayerZeroStatus(data) {
5559
+ const obj = data;
5560
+ if (!obj) return { status: "INFLIGHT" };
5561
+ const messages = obj.messages ?? obj.data ?? [];
5562
+ const msg = Array.isArray(messages) ? messages[0] : messages;
5563
+ if (!msg) return { status: "INFLIGHT" };
5564
+ const lzStatus = (msg.status ?? msg.msgStatus ?? "").toUpperCase();
5565
+ if (lzStatus === "DELIVERED" || lzStatus === "DESTINATION_FINALIZED") {
5566
+ return { status: "DELIVERED", dstTxHash: msg.dstTxHash };
5567
+ }
5568
+ if (lzStatus === "FAILED") return { status: "FAILED" };
5569
+ if (lzStatus === "BLOCKED") return { status: "BLOCKED" };
5570
+ if (lzStatus.includes("CONFIRM")) return { status: "CONFIRMING" };
5571
+ return { status: "INFLIGHT" };
5572
+ }
5573
+
5574
+ // src/bridge.ts
5575
+ var jsonRpcId = 1;
5576
+ async function jsonRpcCall(rpcUrl, method, params) {
5577
+ const id = jsonRpcId++;
5578
+ const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
5579
+ const res = await fetch(rpcUrl, {
5580
+ method: "POST",
5581
+ headers: { "Content-Type": "application/json" },
5582
+ body
5583
+ });
5584
+ if (!res.ok) {
5585
+ throw new Error(`JSON-RPC request failed: ${res.status} ${res.statusText}`);
5586
+ }
5587
+ const json = await res.json();
5588
+ if (json.error) {
5589
+ throw new Error(`JSON-RPC error ${json.error.code}: ${json.error.message}`);
5590
+ }
5591
+ return json.result;
5592
+ }
5593
+ var KNOWN_SELECTORS = {
5594
+ // ERC-20
5595
+ balanceOf: "0x70a08231",
5596
+ allowance: "0xdd62ed3e",
5597
+ approve: "0x095ea7b3",
5598
+ transfer: "0xa9059cbb",
5599
+ // OFT / LayerZero
5600
+ quoteSend: "0x0d35b415",
5601
+ send: "0xc7c7f5b3"
5602
+ };
5603
+ function encodeUint256(value) {
5604
+ return value.toString(16).padStart(64, "0");
5605
+ }
5606
+ function encodeAddress(addr) {
5607
+ const clean = addr.startsWith("0x") ? addr.slice(2) : addr;
5608
+ return clean.toLowerCase().padStart(64, "0");
5609
+ }
5610
+ function encodeFunctionCall(args) {
5611
+ const selector = KNOWN_SELECTORS[args.functionName];
5612
+ if (!selector) {
5613
+ throw new Error(`Unknown function: ${args.functionName}. Cannot encode without full ABI codec.`);
5614
+ }
5615
+ const fnArgs = args.args ?? [];
5616
+ let encoded = selector;
5617
+ for (const arg of fnArgs) {
5618
+ if (typeof arg === "bigint") {
5619
+ encoded += encodeUint256(arg);
5620
+ } else if (typeof arg === "string" && arg.startsWith("0x") && arg.length === 42) {
5621
+ encoded += encodeAddress(arg);
5622
+ } else if (typeof arg === "string" && arg.startsWith("0x")) {
5623
+ const clean = arg.slice(2);
5624
+ encoded += clean.padStart(64, "0");
5625
+ } else if (typeof arg === "number") {
5626
+ encoded += BigInt(arg).toString(16).padStart(64, "0");
5627
+ } else if (typeof arg === "object" && arg !== null) {
5628
+ const obj = arg;
5629
+ for (const val of Object.values(obj)) {
5630
+ if (typeof val === "bigint") {
5631
+ encoded += encodeUint256(val);
5632
+ } else if (typeof val === "string" && val.startsWith("0x")) {
5633
+ const clean = val.slice(2);
5634
+ encoded += clean.padStart(64, "0");
5635
+ } else if (typeof val === "number") {
5636
+ encoded += BigInt(val).toString(16).padStart(64, "0");
5637
+ }
5638
+ }
5639
+ } else {
5640
+ throw new Error(`Cannot encode argument of type ${typeof arg}`);
5641
+ }
5642
+ }
5643
+ return encoded;
5644
+ }
5645
+ function decodeFunctionResult(args, hex) {
5646
+ if (typeof hex !== "string") return hex;
5647
+ const data = hex.startsWith("0x") ? hex.slice(2) : hex;
5648
+ if (data.length === 0) return void 0;
5649
+ const word = data.slice(0, 64);
5650
+ const fnName = args.functionName;
5651
+ if (["balanceOf", "allowance", "totalSupply", "decimals", "nonces"].includes(fnName)) {
5652
+ return BigInt("0x" + word);
5653
+ }
5654
+ if (["approve", "transfer", "transferFrom"].includes(fnName)) {
5655
+ return BigInt("0x" + word) !== 0n;
5656
+ }
5657
+ return hex;
5658
+ }
5659
+ async function pollForReceipt(rpcUrl, hash, timeout) {
5660
+ const pollInterval = 2e3;
5661
+ const deadline = Date.now() + timeout;
5662
+ while (Date.now() < deadline) {
5663
+ const result = await jsonRpcCall(rpcUrl, "eth_getTransactionReceipt", [hash]);
5664
+ if (result) {
5665
+ return {
5666
+ status: result.status === "0x1" ? "success" : "reverted",
5667
+ transactionHash: result.transactionHash,
5668
+ logs: (result.logs ?? []).map((log) => ({
5669
+ address: log.address,
5670
+ topics: log.topics,
5671
+ data: log.data
5672
+ }))
5673
+ };
5674
+ }
5675
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
5676
+ }
5677
+ throw new Error(`Transaction receipt not found after ${timeout}ms: ${hash}`);
5678
+ }
5679
+ var WdkBridge = class {
5680
+ bridges = /* @__PURE__ */ new Map();
5681
+ tracker;
5682
+ constructor(trackerConfig) {
5683
+ this.tracker = new BridgeTracker(trackerConfig);
5684
+ }
5685
+ /**
5686
+ * Create bridge signer adapter from WDK signer.
5687
+ *
5688
+ * Uses JSON-RPC calls for readContract / waitForTransactionReceipt,
5689
+ * and delegates writeContract to the WDK signer's sendTransaction.
5690
+ */
5691
+ createBridgeSigner(signer, rpcUrl) {
5692
+ return {
5693
+ address: signer.address,
5694
+ readContract: async (args) => {
5695
+ const data = encodeFunctionCall(args);
5696
+ const result = await jsonRpcCall(rpcUrl, "eth_call", [{ to: args.address, data }, "latest"]);
5697
+ return decodeFunctionResult(args, result);
5698
+ },
5699
+ writeContract: async (args) => {
5700
+ const data = encodeFunctionCall(args);
5701
+ const { hash } = await signer.sendTransaction({
5702
+ to: args.address,
5703
+ data,
5704
+ value: args.value
5705
+ });
5706
+ return hash;
5707
+ },
5708
+ waitForTransactionReceipt: async (args) => {
5709
+ return pollForReceipt(rpcUrl, args.hash, 6e4);
5710
+ }
5711
+ };
5712
+ }
5713
+ /**
5714
+ * Get or create a bridge instance for a chain
5715
+ *
5716
+ * @param chain - Chain name (e.g., "arbitrum", "ethereum")
5717
+ * @param signer - WDK signer for the chain
5718
+ * @param rpcUrl - JSON-RPC endpoint URL for the chain
5719
+ */
5720
+ getBridge(chain, signer, rpcUrl) {
5721
+ const cached = this.bridges.get(chain);
5722
+ if (cached) {
5723
+ return cached;
5724
+ }
5725
+ const bridgeSigner = this.createBridgeSigner(signer, rpcUrl);
5726
+ const bridge = new import_evm2.Usdt0Bridge(bridgeSigner, chain);
5727
+ this.bridges.set(chain, bridge);
5728
+ return bridge;
5729
+ }
5730
+ /**
5731
+ * Check if a chain supports USDT0 bridging
5732
+ */
5733
+ static supportsBridging(chain) {
5734
+ return (0, import_evm2.supportsBridging)(chain);
5735
+ }
5736
+ /**
5737
+ * Get all chains that support USDT0 bridging
5738
+ */
5739
+ static getBridgeableChains() {
5740
+ return (0, import_evm2.getBridgeableChains)();
5741
+ }
5742
+ /**
5743
+ * Get supported destinations from a source chain
5744
+ */
5745
+ static getSupportedDestinations(fromChain) {
5746
+ return (0, import_evm2.getBridgeableChains)().filter((chain) => chain !== fromChain);
5747
+ }
5748
+ };
5749
+ function createDirectBridge(signer, chain) {
5750
+ return new import_evm2.Usdt0Bridge(signer, chain);
5751
+ }
5752
+
5753
+ // src/logger.ts
5754
+ var defaultLogger = {
5755
+ debug(msg, ctx) {
5756
+ if (ctx && Object.keys(ctx).length > 0) {
5757
+ console.debug(`[t402] ${msg}`, ctx);
5758
+ } else {
5759
+ console.debug(`[t402] ${msg}`);
5760
+ }
5761
+ },
5762
+ info(msg, ctx) {
5763
+ if (ctx && Object.keys(ctx).length > 0) {
5764
+ console.info(`[t402] ${msg}`, ctx);
5765
+ } else {
5766
+ console.info(`[t402] ${msg}`);
5767
+ }
5768
+ },
5769
+ warn(msg, ctx) {
5770
+ if (ctx && Object.keys(ctx).length > 0) {
5771
+ console.warn(`[t402] ${msg}`, ctx);
5772
+ } else {
5773
+ console.warn(`[t402] ${msg}`);
5774
+ }
5775
+ },
5776
+ error(msg, ctx) {
5777
+ if (ctx && Object.keys(ctx).length > 0) {
5778
+ console.error(`[t402] ${msg}`, ctx);
5779
+ } else {
5780
+ console.error(`[t402] ${msg}`);
5781
+ }
5782
+ }
5783
+ };
5784
+ var noopLogger = {
5785
+ debug() {
5786
+ },
5787
+ info() {
5788
+ },
5789
+ warn() {
5790
+ },
5791
+ error() {
5792
+ }
5793
+ };
5794
+ function createCorrelationId() {
5795
+ const bytes = new Uint8Array(8);
5796
+ if (typeof globalThis.crypto?.getRandomValues === "function") {
5797
+ globalThis.crypto.getRandomValues(bytes);
5798
+ } else {
5799
+ for (let i = 0; i < bytes.length; i++) {
5800
+ bytes[i] = Math.floor(Math.random() * 256);
5801
+ }
5802
+ }
5803
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
5804
+ }
5805
+
5806
+ // src/index.ts
5807
+ var import_evm3 = require("@t402/evm");
5808
+
5809
+ // src/compatibility.ts
5810
+ var WDK_COMPATIBILITY = {
5811
+ /** Minimum supported @tetherto/wdk version */
5812
+ minVersion: "1.0.0-beta.0",
5813
+ /** Versions that have been tested */
5814
+ testedVersions: ["1.0.0-beta.3", "1.0.0-beta.4", "1.0.0-beta.5"],
5815
+ /** Tested wallet-evm module versions */
5816
+ walletEvmVersions: ["1.0.0-beta.5", "2.0.0-rc.1"],
5817
+ /** Feature availability by @tetherto/wdk core version */
5818
+ features: {
5819
+ signTypedData: "1.0.0-beta.0",
5820
+ estimateGas: "1.0.0-beta.3",
5821
+ multiChainWallets: "1.0.0-beta.0",
5822
+ bridgeProtocol: "1.0.0-beta.3",
5823
+ swapProtocol: "1.0.0-beta.4"
5824
+ },
5825
+ /** Known wallet module minimum versions */
5826
+ walletModuleVersions: {
5827
+ evm: "1.0.0-beta.5",
5828
+ ton: "1.0.0-beta.7",
5829
+ btc: "1.0.0-beta.5",
5830
+ tron: "1.0.0-beta.4",
5831
+ solana: "1.0.0-beta.5",
5832
+ spark: "1.0.0-beta.6"
5833
+ }
5834
+ };
5835
+ function parseVersion(version) {
5836
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
5837
+ if (!match) {
5838
+ return { major: 0, minor: 0, patch: 0, prerelease: "" };
5839
+ }
5840
+ return {
5841
+ major: parseInt(match[1], 10),
5842
+ minor: parseInt(match[2], 10),
5843
+ patch: parseInt(match[3], 10),
5844
+ prerelease: match[4] ?? ""
5845
+ };
5846
+ }
5847
+ function compareVersions(a, b) {
5848
+ const va = parseVersion(a);
5849
+ const vb = parseVersion(b);
5850
+ if (va.major !== vb.major) return va.major < vb.major ? -1 : 1;
5851
+ if (va.minor !== vb.minor) return va.minor < vb.minor ? -1 : 1;
5852
+ if (va.patch !== vb.patch) return va.patch < vb.patch ? -1 : 1;
5853
+ if (va.prerelease && !vb.prerelease) return -1;
5854
+ if (!va.prerelease && vb.prerelease) return 1;
5855
+ if (va.prerelease && vb.prerelease) {
5856
+ return va.prerelease < vb.prerelease ? -1 : va.prerelease > vb.prerelease ? 1 : 0;
5857
+ }
5858
+ return 0;
5859
+ }
5860
+ function checkWdkCompatibility(version) {
5861
+ const warnings = [];
5862
+ if (compareVersions(version, WDK_COMPATIBILITY.minVersion) < 0) {
5863
+ return {
5864
+ compatible: false,
5865
+ warnings: [
5866
+ `@tetherto/wdk ${version} is below minimum supported version ${WDK_COMPATIBILITY.minVersion}`
5867
+ ]
5868
+ };
5869
+ }
5870
+ const isTested = WDK_COMPATIBILITY.testedVersions.includes(version);
5871
+ if (!isTested) {
5872
+ warnings.push(
5873
+ `@tetherto/wdk ${version} has not been explicitly tested. Tested versions: ${WDK_COMPATIBILITY.testedVersions.join(", ")}`
5874
+ );
5875
+ }
5876
+ for (const [feature, minFeatureVersion] of Object.entries(WDK_COMPATIBILITY.features)) {
5877
+ if (compareVersions(version, minFeatureVersion) < 0) {
5878
+ warnings.push(`Feature '${feature}' requires @tetherto/wdk >= ${minFeatureVersion}`);
5879
+ }
5880
+ }
5881
+ return { compatible: true, warnings };
5882
+ }
5883
+ function checkWalletEvmCompatibility(version) {
5884
+ const warnings = [];
5885
+ const isTested = WDK_COMPATIBILITY.walletEvmVersions.includes(version);
5886
+ if (!isTested) {
5887
+ warnings.push(
5888
+ `@tetherto/wdk-wallet-evm ${version} has not been explicitly tested. Tested versions: ${WDK_COMPATIBILITY.walletEvmVersions.join(", ")}`
5889
+ );
5890
+ }
5891
+ return { compatible: true, warnings };
5892
+ }
5893
+ function getWalletModuleMinVersion(module2) {
5894
+ return WDK_COMPATIBILITY.walletModuleVersions[module2];
5895
+ }
5896
+
5897
+ // src/idempotency.ts
5898
+ var InMemoryIdempotencyManager = class {
5899
+ _payments = /* @__PURE__ */ new Map();
5900
+ _nonces = /* @__PURE__ */ new Map();
5901
+ _recentTxHashes;
5902
+ _maxRecentTxHashes;
5903
+ /**
5904
+ * @param maxRecentTxHashes - Maximum number of recent tx hashes to track for dedup (default: 1000)
5905
+ */
5906
+ constructor(maxRecentTxHashes = 1e3) {
5907
+ this._recentTxHashes = /* @__PURE__ */ new Set();
5908
+ this._maxRecentTxHashes = maxRecentTxHashes;
5909
+ }
5910
+ async checkDuplicate(key) {
5911
+ return this._payments.has(key);
5912
+ }
5913
+ async recordPayment(key, receipt) {
5914
+ this._payments.set(key, receipt);
5915
+ if (receipt.txHash) {
5916
+ this._addTxHash(receipt.txHash);
5917
+ }
5918
+ }
5919
+ async getNonce(address, chain) {
5920
+ const key = this._nonceKey(address, chain);
5921
+ return this._nonces.get(key) ?? 0n;
5922
+ }
5923
+ async incrementNonce(address, chain) {
5924
+ const key = this._nonceKey(address, chain);
5925
+ const current = this._nonces.get(key) ?? 0n;
5926
+ const next = current + 1n;
5927
+ this._nonces.set(key, next);
5928
+ return next;
5929
+ }
5930
+ /**
5931
+ * Check if a transaction hash has been seen recently
5932
+ */
5933
+ hasTxHash(txHash) {
5934
+ return this._recentTxHashes.has(txHash.toLowerCase());
5935
+ }
5936
+ /**
5937
+ * Get a recorded payment by its idempotency key
5938
+ */
5939
+ getPayment(key) {
5940
+ return this._payments.get(key);
5941
+ }
5942
+ /**
5943
+ * Get the number of recorded payments
5944
+ */
5945
+ get size() {
5946
+ return this._payments.size;
5947
+ }
5948
+ /**
5949
+ * Clear all recorded payments and nonces
5950
+ */
5951
+ clear() {
5952
+ this._payments.clear();
5953
+ this._nonces.clear();
5954
+ this._recentTxHashes.clear();
5955
+ }
5956
+ _nonceKey(address, chain) {
5957
+ return `${chain}:${address.toLowerCase()}`;
5958
+ }
5959
+ _addTxHash(txHash) {
5960
+ const normalized = txHash.toLowerCase();
5961
+ if (this._recentTxHashes.size >= this._maxRecentTxHashes) {
5962
+ const first = this._recentTxHashes.values().next().value;
5963
+ if (first !== void 0) {
5964
+ this._recentTxHashes.delete(first);
5965
+ }
5966
+ }
5967
+ this._recentTxHashes.add(normalized);
5968
+ }
5969
+ };
5970
+ var NonceManager = class {
5971
+ _nonces = /* @__PURE__ */ new Map();
5972
+ /**
5973
+ * Get the current nonce for an address on a chain.
5974
+ * If no cached value exists, uses the provided fetcher to query on-chain.
5975
+ *
5976
+ * @param address - Wallet address
5977
+ * @param chain - Chain identifier
5978
+ * @param fetchOnChainNonce - Optional function to query the on-chain nonce
5979
+ */
5980
+ async getNonce(address, chain, fetchOnChainNonce) {
5981
+ const key = this._key(address, chain);
5982
+ const cached = this._nonces.get(key);
5983
+ if (cached !== void 0) {
5984
+ return cached;
5985
+ }
5986
+ if (fetchOnChainNonce) {
5987
+ const onChainNonce = await fetchOnChainNonce();
5988
+ this._nonces.set(key, onChainNonce);
5989
+ return onChainNonce;
5990
+ }
5991
+ return 0n;
5992
+ }
5993
+ /**
5994
+ * Increment the nonce after a successful signature/transaction
5995
+ */
5996
+ increment(address, chain) {
5997
+ const key = this._key(address, chain);
5998
+ const current = this._nonces.get(key) ?? 0n;
5999
+ const next = current + 1n;
6000
+ this._nonces.set(key, next);
6001
+ return next;
6002
+ }
6003
+ /**
6004
+ * Set the nonce to a specific value (e.g., after querying on-chain)
6005
+ */
6006
+ set(address, chain, nonce) {
6007
+ const key = this._key(address, chain);
6008
+ this._nonces.set(key, nonce);
6009
+ }
6010
+ /**
6011
+ * Reset the nonce for an address on a chain (forces re-fetch on next use)
6012
+ */
6013
+ reset(address, chain) {
6014
+ const key = this._key(address, chain);
6015
+ this._nonces.delete(key);
6016
+ }
6017
+ /**
6018
+ * Clear all cached nonces
6019
+ */
6020
+ clear() {
6021
+ this._nonces.clear();
6022
+ }
6023
+ _key(address, chain) {
6024
+ return `${chain}:${address.toLowerCase()}`;
6025
+ }
6026
+ };
6027
+ function generateIdempotencyKey(params) {
6028
+ return `${params.from.toLowerCase()}:${params.payTo.toLowerCase()}:${params.network}:${params.amount}:${params.url}`;
6029
+ }
6030
+
6031
+ // src/compliance.ts
6032
+ var ComplianceManager = class {
6033
+ _providers = [];
6034
+ _auditTrail = [];
6035
+ /**
6036
+ * Register a compliance provider
6037
+ */
6038
+ registerProvider(provider) {
6039
+ this._providers.push(provider);
6040
+ }
6041
+ /**
6042
+ * Run all registered providers against the given parameters.
6043
+ * Returns the first rejection, or `{ allowed: true }` if all pass.
6044
+ *
6045
+ * @param params - The transaction parameters to check
6046
+ * @param action - The type of action being performed (default: 'payment')
6047
+ */
6048
+ async check(params, action = "payment") {
6049
+ if (this._providers.length === 0) {
6050
+ const result2 = { allowed: true };
6051
+ this._recordEvent(action, params, result2);
6052
+ return result2;
6053
+ }
6054
+ for (const provider of this._providers) {
6055
+ const result2 = await provider.check(params);
6056
+ if (!result2.allowed) {
6057
+ this._recordEvent(action, params, result2);
6058
+ return result2;
6059
+ }
6060
+ }
6061
+ const result = { allowed: true };
6062
+ this._recordEvent(action, params, result);
6063
+ return result;
6064
+ }
6065
+ /**
6066
+ * Get the full audit trail of compliance checks
6067
+ */
6068
+ getAuditTrail() {
6069
+ return [...this._auditTrail];
6070
+ }
6071
+ /**
6072
+ * Clear the audit trail
6073
+ */
6074
+ clearAuditTrail() {
6075
+ this._auditTrail = [];
6076
+ }
6077
+ /**
6078
+ * Get the number of registered providers
6079
+ */
6080
+ get providerCount() {
6081
+ return this._providers.length;
6082
+ }
6083
+ _recordEvent(action, params, result) {
6084
+ this._auditTrail.push({
6085
+ timestamp: Date.now(),
6086
+ action,
6087
+ params,
6088
+ result
6089
+ });
6090
+ }
6091
+ };
6092
+ var BlacklistProvider = class {
6093
+ _addresses;
6094
+ constructor(addresses) {
6095
+ this._addresses = /* @__PURE__ */ new Set();
6096
+ if (addresses) {
6097
+ for (const addr of addresses) {
6098
+ this._addresses.add(addr.toLowerCase());
6099
+ }
6100
+ }
6101
+ }
6102
+ async check(params) {
6103
+ const fromLower = params.from.toLowerCase();
6104
+ const toLower = params.to.toLowerCase();
6105
+ if (this._addresses.has(fromLower)) {
6106
+ return { allowed: false, reason: `Address ${params.from} is blacklisted (sender)` };
6107
+ }
6108
+ if (this._addresses.has(toLower)) {
6109
+ return { allowed: false, reason: `Address ${params.to} is blacklisted (recipient)` };
6110
+ }
6111
+ return { allowed: true };
6112
+ }
6113
+ /**
6114
+ * Add an address to the blacklist
6115
+ */
6116
+ addAddress(address) {
6117
+ this._addresses.add(address.toLowerCase());
6118
+ }
6119
+ /**
6120
+ * Remove an address from the blacklist
6121
+ */
6122
+ removeAddress(address) {
6123
+ this._addresses.delete(address.toLowerCase());
6124
+ }
6125
+ /**
6126
+ * Check if an address is blacklisted
6127
+ */
6128
+ hasAddress(address) {
6129
+ return this._addresses.has(address.toLowerCase());
6130
+ }
6131
+ /**
6132
+ * Get the number of blacklisted addresses
6133
+ */
6134
+ get size() {
6135
+ return this._addresses.size;
6136
+ }
6137
+ };
6138
+ var AmountLimitProvider = class {
6139
+ _maxPerTransaction;
6140
+ _cumulativeAmounts = /* @__PURE__ */ new Map();
6141
+ _maxCumulative;
6142
+ /**
6143
+ * @param maxPerTransaction - Maximum amount per single transaction
6144
+ * @param maxCumulative - Optional maximum cumulative amount per address
6145
+ */
6146
+ constructor(maxPerTransaction, maxCumulative) {
6147
+ this._maxPerTransaction = maxPerTransaction;
6148
+ this._maxCumulative = maxCumulative;
6149
+ }
6150
+ async check(params) {
6151
+ if (params.amount > this._maxPerTransaction) {
6152
+ return {
6153
+ allowed: false,
6154
+ reason: `Amount ${params.amount} exceeds per-transaction limit of ${this._maxPerTransaction}`
6155
+ };
6156
+ }
6157
+ if (this._maxCumulative !== void 0) {
6158
+ const key = params.from.toLowerCase();
6159
+ const cumulative = (this._cumulativeAmounts.get(key) ?? 0n) + params.amount;
6160
+ if (cumulative > this._maxCumulative) {
6161
+ return {
6162
+ allowed: false,
6163
+ reason: `Cumulative amount ${cumulative} would exceed limit of ${this._maxCumulative}`
6164
+ };
6165
+ }
6166
+ this._cumulativeAmounts.set(key, cumulative);
6167
+ }
6168
+ return { allowed: true };
6169
+ }
6170
+ /**
6171
+ * Reset cumulative tracking for an address
6172
+ */
6173
+ resetCumulative(address) {
6174
+ this._cumulativeAmounts.delete(address.toLowerCase());
6175
+ }
6176
+ /**
6177
+ * Reset all cumulative tracking
6178
+ */
6179
+ resetAllCumulative() {
6180
+ this._cumulativeAmounts.clear();
6181
+ }
6182
+ };
6183
+
6184
+ // src/webhooks.ts
6185
+ var WebhookManager = class {
6186
+ _configs;
6187
+ _deliveryResults = [];
6188
+ _maxDeliveryHistory;
6189
+ /**
6190
+ * @param configs - Array of webhook endpoint configurations
6191
+ * @param maxDeliveryHistory - Maximum number of delivery results to retain (default: 100)
6192
+ */
6193
+ constructor(configs, maxDeliveryHistory = 100) {
6194
+ this._configs = configs;
6195
+ this._maxDeliveryHistory = maxDeliveryHistory;
6196
+ }
6197
+ /**
6198
+ * Send a webhook event to all subscribed endpoints
6199
+ *
6200
+ * @param event - Event type (e.g., 'payment.completed')
6201
+ * @param payload - Event payload data
6202
+ * @returns Array of delivery results for each endpoint
6203
+ */
6204
+ async send(event, payload) {
6205
+ const results = [];
6206
+ for (const config of this._configs) {
6207
+ if (config.events && config.events.length > 0 && !config.events.includes(event)) {
6208
+ continue;
6209
+ }
6210
+ const result = await this._deliver(config, event, payload);
6211
+ results.push(result);
6212
+ this._recordResult(result);
6213
+ }
6214
+ return results;
6215
+ }
6216
+ /**
6217
+ * Sign a payload with HMAC-SHA256
6218
+ *
6219
+ * @param payload - The payload to sign (will be JSON.stringify'd if not a string)
6220
+ * @param secret - The secret key
6221
+ * @returns Hex-encoded HMAC-SHA256 signature
6222
+ */
6223
+ signPayload(payload, secret) {
6224
+ const crypto = require("crypto");
6225
+ const data = typeof payload === "string" ? payload : JSON.stringify(payload);
6226
+ return crypto.createHmac("sha256", secret).update(data).digest("hex");
6227
+ }
6228
+ /**
6229
+ * Verify an HMAC-SHA256 signature on a payload
6230
+ *
6231
+ * @param payload - The raw payload string
6232
+ * @param signature - The signature to verify
6233
+ * @param secret - The secret key
6234
+ * @returns True if the signature is valid
6235
+ */
6236
+ verifySignature(payload, signature, secret) {
6237
+ const expected = this.signPayload(payload, secret);
6238
+ if (expected.length !== signature.length) {
6239
+ return false;
6240
+ }
6241
+ const crypto = require("crypto");
6242
+ return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(signature, "hex"));
3100
6243
  }
3101
6244
  /**
3102
- * Check if a chain supports USDT0 bridging
6245
+ * Get recent delivery results
3103
6246
  */
3104
- static supportsBridging(chain) {
3105
- return (0, import_evm2.supportsBridging)(chain);
6247
+ getDeliveryResults() {
6248
+ return [...this._deliveryResults];
3106
6249
  }
3107
6250
  /**
3108
- * Get all chains that support USDT0 bridging
6251
+ * Clear delivery history
3109
6252
  */
3110
- static getBridgeableChains() {
3111
- return (0, import_evm2.getBridgeableChains)();
6253
+ clearDeliveryResults() {
6254
+ this._deliveryResults = [];
3112
6255
  }
3113
6256
  /**
3114
- * Get supported destinations from a source chain
6257
+ * Get the number of configured webhook endpoints
3115
6258
  */
3116
- static getSupportedDestinations(fromChain) {
3117
- return (0, import_evm2.getBridgeableChains)().filter((chain) => chain !== fromChain);
6259
+ get endpointCount() {
6260
+ return this._configs.length;
3118
6261
  }
3119
- };
3120
- function createDirectBridge(signer, chain) {
3121
- return new import_evm2.Usdt0Bridge(signer, chain);
3122
- }
3123
-
3124
- // src/index.ts
3125
- var import_evm3 = require("@t402/evm");
3126
-
3127
- // src/compatibility.ts
3128
- var WDK_COMPATIBILITY = {
3129
- /** Minimum supported @tetherto/wdk version */
3130
- minVersion: "1.0.0-beta.0",
3131
- /** Versions that have been tested */
3132
- testedVersions: ["1.0.0-beta.3", "1.0.0-beta.4", "1.0.0-beta.5"],
3133
- /** Tested wallet-evm module versions */
3134
- walletEvmVersions: ["1.0.0-beta.5", "2.0.0-rc.1"],
3135
- /** Feature availability by @tetherto/wdk core version */
3136
- features: {
3137
- signTypedData: "1.0.0-beta.0",
3138
- estimateGas: "1.0.0-beta.3",
3139
- multiChainWallets: "1.0.0-beta.0",
3140
- bridgeProtocol: "1.0.0-beta.3",
3141
- swapProtocol: "1.0.0-beta.4"
3142
- },
3143
- /** Known wallet module minimum versions */
3144
- walletModuleVersions: {
3145
- evm: "1.0.0-beta.5",
3146
- ton: "1.0.0-beta.7",
3147
- btc: "1.0.0-beta.5",
3148
- tron: "1.0.0-beta.4",
3149
- solana: "1.0.0-beta.5",
3150
- spark: "1.0.0-beta.6"
6262
+ async _deliver(config, event, payload) {
6263
+ const maxRetries = config.retries ?? 3;
6264
+ const body = JSON.stringify({ event, timestamp: (/* @__PURE__ */ new Date()).toISOString(), data: payload });
6265
+ const signature = this.signPayload(body, config.secret);
6266
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
6267
+ try {
6268
+ const response = await fetch(config.url, {
6269
+ method: "POST",
6270
+ headers: {
6271
+ "Content-Type": "application/json",
6272
+ "X-Webhook-Signature": signature,
6273
+ "X-Webhook-Event": event
6274
+ },
6275
+ body
6276
+ });
6277
+ if (response.ok) {
6278
+ return {
6279
+ url: config.url,
6280
+ success: true,
6281
+ statusCode: response.status,
6282
+ attempts: attempt
6283
+ };
6284
+ }
6285
+ if (response.status >= 400 && response.status < 500) {
6286
+ return {
6287
+ url: config.url,
6288
+ success: false,
6289
+ statusCode: response.status,
6290
+ error: `HTTP ${response.status}`,
6291
+ attempts: attempt
6292
+ };
6293
+ }
6294
+ if (attempt === maxRetries) {
6295
+ return {
6296
+ url: config.url,
6297
+ success: false,
6298
+ statusCode: response.status,
6299
+ error: `HTTP ${response.status} after ${maxRetries} attempts`,
6300
+ attempts: attempt
6301
+ };
6302
+ }
6303
+ await this._sleep(Math.min(1e3 * Math.pow(2, attempt - 1), 1e4));
6304
+ } catch (error) {
6305
+ if (attempt === maxRetries) {
6306
+ return {
6307
+ url: config.url,
6308
+ success: false,
6309
+ error: error instanceof Error ? error.message : String(error),
6310
+ attempts: attempt
6311
+ };
6312
+ }
6313
+ await this._sleep(Math.min(1e3 * Math.pow(2, attempt - 1), 1e4));
6314
+ }
6315
+ }
6316
+ return {
6317
+ url: config.url,
6318
+ success: false,
6319
+ error: "Max retries exceeded",
6320
+ attempts: maxRetries
6321
+ };
3151
6322
  }
3152
- };
3153
- function parseVersion(version) {
3154
- const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
3155
- if (!match) {
3156
- return { major: 0, minor: 0, patch: 0, prerelease: "" };
6323
+ _recordResult(result) {
6324
+ this._deliveryResults.push(result);
6325
+ while (this._deliveryResults.length > this._maxDeliveryHistory) {
6326
+ this._deliveryResults.shift();
6327
+ }
3157
6328
  }
3158
- return {
3159
- major: parseInt(match[1], 10),
3160
- minor: parseInt(match[2], 10),
3161
- patch: parseInt(match[3], 10),
3162
- prerelease: match[4] ?? ""
3163
- };
3164
- }
3165
- function compareVersions(a, b) {
3166
- const va = parseVersion(a);
3167
- const vb = parseVersion(b);
3168
- if (va.major !== vb.major) return va.major < vb.major ? -1 : 1;
3169
- if (va.minor !== vb.minor) return va.minor < vb.minor ? -1 : 1;
3170
- if (va.patch !== vb.patch) return va.patch < vb.patch ? -1 : 1;
3171
- if (va.prerelease && !vb.prerelease) return -1;
3172
- if (!va.prerelease && vb.prerelease) return 1;
3173
- if (va.prerelease && vb.prerelease) {
3174
- return va.prerelease < vb.prerelease ? -1 : va.prerelease > vb.prerelease ? 1 : 0;
6329
+ _sleep(ms) {
6330
+ return new Promise((resolve) => setTimeout(resolve, ms));
3175
6331
  }
3176
- return 0;
3177
- }
3178
- function checkWdkCompatibility(version) {
3179
- const warnings = [];
3180
- if (compareVersions(version, WDK_COMPATIBILITY.minVersion) < 0) {
3181
- return {
3182
- compatible: false,
3183
- warnings: [
3184
- `@tetherto/wdk ${version} is below minimum supported version ${WDK_COMPATIBILITY.minVersion}`
3185
- ]
3186
- };
6332
+ };
6333
+
6334
+ // src/indexer.ts
6335
+ var WdkIndexerVerifier = class {
6336
+ endpoint;
6337
+ apiKey;
6338
+ timeout;
6339
+ constructor(config) {
6340
+ if (!config.endpoint) {
6341
+ throw new Error("Indexer endpoint is required");
6342
+ }
6343
+ this.endpoint = config.endpoint.replace(/\/$/, "");
6344
+ this.apiKey = config.apiKey;
6345
+ this.timeout = config.timeout ?? 1e4;
3187
6346
  }
3188
- const isTested = WDK_COMPATIBILITY.testedVersions.includes(version);
3189
- if (!isTested) {
3190
- warnings.push(
3191
- `@tetherto/wdk ${version} has not been explicitly tested. Tested versions: ${WDK_COMPATIBILITY.testedVersions.join(", ")}`
3192
- );
6347
+ /**
6348
+ * Query a transaction across any supported chain
6349
+ */
6350
+ async queryTransaction(query) {
6351
+ if (!query.txHash) {
6352
+ throw new Error("Transaction hash is required");
6353
+ }
6354
+ if (!query.network) {
6355
+ throw new Error("Network is required");
6356
+ }
6357
+ const url = `${this.endpoint}/v1/transactions/${encodeURIComponent(query.network)}/${encodeURIComponent(query.txHash)}`;
6358
+ const headers = {
6359
+ "Content-Type": "application/json"
6360
+ };
6361
+ if (this.apiKey) {
6362
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
6363
+ }
6364
+ const controller = new AbortController();
6365
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6366
+ try {
6367
+ const response = await fetch(url, {
6368
+ method: "GET",
6369
+ headers,
6370
+ signal: controller.signal
6371
+ });
6372
+ if (!response.ok) {
6373
+ if (response.status === 404) {
6374
+ return {
6375
+ found: false,
6376
+ confirmed: false,
6377
+ from: "",
6378
+ to: "",
6379
+ amount: "0",
6380
+ token: ""
6381
+ };
6382
+ }
6383
+ throw new Error(`Indexer request failed: ${response.status} ${response.statusText}`);
6384
+ }
6385
+ const data = await response.json();
6386
+ return {
6387
+ found: true,
6388
+ confirmed: data.confirmed ?? data.status === "confirmed",
6389
+ from: data.from ?? "",
6390
+ to: data.to ?? "",
6391
+ amount: String(data.amount ?? data.value ?? "0"),
6392
+ token: data.token ?? data.tokenAddress ?? "",
6393
+ blockNumber: data.blockNumber ?? data.block_number,
6394
+ timestamp: data.timestamp ?? data.block_timestamp
6395
+ };
6396
+ } catch (error) {
6397
+ if (error.name === "AbortError") {
6398
+ throw new Error(`Indexer request timed out after ${this.timeout}ms`);
6399
+ }
6400
+ throw error;
6401
+ } finally {
6402
+ clearTimeout(timeoutId);
6403
+ }
3193
6404
  }
3194
- for (const [feature, minFeatureVersion] of Object.entries(WDK_COMPATIBILITY.features)) {
3195
- if (compareVersions(version, minFeatureVersion) < 0) {
3196
- warnings.push(`Feature '${feature}' requires @tetherto/wdk >= ${minFeatureVersion}`);
6405
+ /**
6406
+ * Verify a transaction matches expected payment parameters
6407
+ */
6408
+ async verifyPayment(query) {
6409
+ const result = await this.queryTransaction(query);
6410
+ if (!result.found) {
6411
+ return { verified: false, reason: "Transaction not found" };
3197
6412
  }
6413
+ if (!result.confirmed) {
6414
+ return { verified: false, reason: "Transaction not yet confirmed" };
6415
+ }
6416
+ if (query.expectedTo) {
6417
+ const normalizedExpected = query.expectedTo.toLowerCase();
6418
+ const normalizedActual = result.to.toLowerCase();
6419
+ if (normalizedActual !== normalizedExpected) {
6420
+ return {
6421
+ verified: false,
6422
+ reason: `Recipient mismatch: expected ${query.expectedTo}, got ${result.to}`
6423
+ };
6424
+ }
6425
+ }
6426
+ if (query.expectedAmount) {
6427
+ const expected = BigInt(query.expectedAmount);
6428
+ const actual = BigInt(result.amount);
6429
+ if (actual < expected) {
6430
+ return {
6431
+ verified: false,
6432
+ reason: `Amount insufficient: expected ${query.expectedAmount}, got ${result.amount}`
6433
+ };
6434
+ }
6435
+ }
6436
+ return { verified: true };
3198
6437
  }
3199
- return { compatible: true, warnings };
3200
- }
3201
- function checkWalletEvmCompatibility(version) {
3202
- const warnings = [];
3203
- const isTested = WDK_COMPATIBILITY.walletEvmVersions.includes(version);
3204
- if (!isTested) {
3205
- warnings.push(
3206
- `@tetherto/wdk-wallet-evm ${version} has not been explicitly tested. Tested versions: ${WDK_COMPATIBILITY.walletEvmVersions.join(", ")}`
3207
- );
6438
+ /**
6439
+ * Check indexer health
6440
+ */
6441
+ async healthCheck() {
6442
+ const controller = new AbortController();
6443
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
6444
+ try {
6445
+ const headers = {};
6446
+ if (this.apiKey) {
6447
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
6448
+ }
6449
+ const response = await fetch(`${this.endpoint}/health`, {
6450
+ method: "GET",
6451
+ headers,
6452
+ signal: controller.signal
6453
+ });
6454
+ return response.ok;
6455
+ } catch {
6456
+ return false;
6457
+ } finally {
6458
+ clearTimeout(timeoutId);
6459
+ }
3208
6460
  }
3209
- return { compatible: true, warnings };
3210
- }
3211
- function getWalletModuleMinVersion(module2) {
3212
- return WDK_COMPATIBILITY.walletModuleVersions[module2];
6461
+ };
6462
+ function createIndexerVerifier(config) {
6463
+ return new WdkIndexerVerifier(config);
3213
6464
  }
3214
6465
 
3215
6466
  // src/hardware/types.ts
@@ -3834,26 +7085,390 @@ function isHardwareWalletSupported() {
3834
7085
  const support = detectHardwareWalletSupport();
3835
7086
  return support.ledger.webusb || support.ledger.webhid || support.ledger.bluetooth || support.trezor;
3836
7087
  }
7088
+
7089
+ // src/providers/moonpay.ts
7090
+ var NETWORK_TO_MOONPAY_CURRENCY = {
7091
+ "eip155:1": "usdt",
7092
+ "eip155:42161": "usdt_arbitrum",
7093
+ "eip155:137": "usdt_polygon",
7094
+ "eip155:8453": "usdt_base",
7095
+ "eip155:10": "usdt_optimism",
7096
+ "eip155:43114": "usdt_avalanche_c_chain",
7097
+ "eip155:56": "usdt_bsc"
7098
+ };
7099
+ var SUPPORTED_FIAT_CURRENCIES = ["USD", "EUR", "GBP"];
7100
+ var SUPPORTED_NETWORKS = Object.keys(NETWORK_TO_MOONPAY_CURRENCY);
7101
+ var BASE_URLS = {
7102
+ production: "https://buy.moonpay.com",
7103
+ sandbox: "https://buy-sandbox.moonpay.com"
7104
+ };
7105
+ var API_URLS = {
7106
+ production: "https://api.moonpay.com",
7107
+ sandbox: "https://api.moonpay.com"
7108
+ };
7109
+ var MoonpayOnRampProvider = class {
7110
+ name = "moonpay";
7111
+ _apiKey;
7112
+ _environment;
7113
+ constructor(config) {
7114
+ if (!config.apiKey) {
7115
+ throw new Error("Moonpay API key is required");
7116
+ }
7117
+ this._apiKey = config.apiKey;
7118
+ this._environment = config.environment ?? "production";
7119
+ }
7120
+ /**
7121
+ * Get the base widget URL for the current environment
7122
+ */
7123
+ get baseUrl() {
7124
+ return BASE_URLS[this._environment];
7125
+ }
7126
+ /**
7127
+ * Get the API base URL for the current environment
7128
+ */
7129
+ get apiUrl() {
7130
+ return API_URLS[this._environment];
7131
+ }
7132
+ /**
7133
+ * Get a quote for fiat-to-crypto conversion
7134
+ *
7135
+ * This method fetches a real-time quote from Moonpay.
7136
+ * Override `_fetchQuote` for testing.
7137
+ */
7138
+ async getQuote(params) {
7139
+ const currencyCode = this._getCurrencyCode(params.network);
7140
+ if (!currencyCode) {
7141
+ throw new Error(`Network "${params.network}" is not supported by Moonpay`);
7142
+ }
7143
+ if (params.fiatAmount <= 0) {
7144
+ throw new Error("fiatAmount must be greater than 0");
7145
+ }
7146
+ if (!SUPPORTED_FIAT_CURRENCIES.includes(params.fiatCurrency.toUpperCase())) {
7147
+ throw new Error(
7148
+ `Currency "${params.fiatCurrency}" is not supported. Supported: ${SUPPORTED_FIAT_CURRENCIES.join(", ")}`
7149
+ );
7150
+ }
7151
+ const quoteUrl = `${this.apiUrl}/v3/currencies/${currencyCode}/buy_quote?apiKey=${this._apiKey}&baseCurrencyAmount=${params.fiatAmount}&baseCurrencyCode=${params.fiatCurrency.toLowerCase()}`;
7152
+ const data = await this._fetchQuote(quoteUrl);
7153
+ return {
7154
+ fiatAmount: params.fiatAmount,
7155
+ fiatCurrency: params.fiatCurrency.toUpperCase(),
7156
+ cryptoAmount: String(data.quoteCurrencyAmount ?? "0"),
7157
+ cryptoCurrency: "USDT",
7158
+ exchangeRate: Number(data.quoteCurrencyPrice ?? 1),
7159
+ fees: {
7160
+ network: String(data.networkFeeAmount ?? "0"),
7161
+ service: String(data.feeAmount ?? "0"),
7162
+ total: String(data.totalFeeAmount ?? "0")
7163
+ },
7164
+ estimatedTime: 600
7165
+ // ~10 minutes typical for card purchases
7166
+ };
7167
+ }
7168
+ /**
7169
+ * Fetch quote from Moonpay API (override in tests)
7170
+ */
7171
+ async _fetchQuote(url) {
7172
+ const response = await fetch(url);
7173
+ if (!response.ok) {
7174
+ throw new Error(`Moonpay API error: ${response.status} ${response.statusText}`);
7175
+ }
7176
+ return response.json();
7177
+ }
7178
+ /**
7179
+ * Create a Moonpay widget URL for the user
7180
+ */
7181
+ createWidget(params) {
7182
+ const currencyCode = this._getCurrencyCode(params.network);
7183
+ if (!currencyCode) {
7184
+ throw new Error(`Network "${params.network}" is not supported by Moonpay`);
7185
+ }
7186
+ if (!params.walletAddress) {
7187
+ throw new Error("walletAddress is required");
7188
+ }
7189
+ if (params.fiatAmount <= 0) {
7190
+ throw new Error("fiatAmount must be greater than 0");
7191
+ }
7192
+ const queryParams = new URLSearchParams({
7193
+ apiKey: this._apiKey,
7194
+ currencyCode,
7195
+ baseCurrencyCode: params.fiatCurrency.toLowerCase(),
7196
+ baseCurrencyAmount: String(params.fiatAmount),
7197
+ walletAddress: params.walletAddress
7198
+ });
7199
+ if (params.redirectUrl) {
7200
+ queryParams.set("redirectURL", params.redirectUrl);
7201
+ }
7202
+ const widgetUrl = `${this.baseUrl}?${queryParams.toString()}`;
7203
+ const orderId = `mp_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
7204
+ const expiresAt = new Date(Date.now() + 30 * 60 * 1e3).toISOString();
7205
+ return { widgetUrl, orderId, expiresAt };
7206
+ }
7207
+ /**
7208
+ * Get supported fiat currencies
7209
+ */
7210
+ getSupportedCurrencies() {
7211
+ return [...SUPPORTED_FIAT_CURRENCIES];
7212
+ }
7213
+ /**
7214
+ * Get supported CAIP-2 networks
7215
+ */
7216
+ getSupportedNetworks() {
7217
+ return [...SUPPORTED_NETWORKS];
7218
+ }
7219
+ /**
7220
+ * Map CAIP-2 network to Moonpay currency code
7221
+ */
7222
+ _getCurrencyCode(network) {
7223
+ return NETWORK_TO_MOONPAY_CURRENCY[network];
7224
+ }
7225
+ };
7226
+ function getMoonpayCurrencyCode(network) {
7227
+ return NETWORK_TO_MOONPAY_CURRENCY[network];
7228
+ }
7229
+
7230
+ // src/integrations/a2a-adapter.ts
7231
+ function findBestOption(accepts, signers, preferredScheme) {
7232
+ const signerNetworks = new Set(signers.map((s) => s.network));
7233
+ const exactMatch = accepts.find(
7234
+ (a) => a.scheme === preferredScheme && signerNetworks.has(a.network)
7235
+ );
7236
+ if (exactMatch) return exactMatch;
7237
+ const networkMatch = accepts.find((a) => signerNetworks.has(a.network));
7238
+ if (networkMatch) return networkMatch;
7239
+ const schemeMatch = accepts.find((a) => a.scheme === preferredScheme);
7240
+ if (schemeMatch) return schemeMatch;
7241
+ return accepts[0];
7242
+ }
7243
+ async function createWdkA2APaymentClient(wdk, options) {
7244
+ const preferredScheme = options?.preferredScheme ?? "exact";
7245
+ const signers = await wdk.getAllSigners({ schemes: [preferredScheme] });
7246
+ const paymentHandler = async (req) => {
7247
+ if (!req.accepts || req.accepts.length === 0) {
7248
+ throw new Error("No payment options in requirements");
7249
+ }
7250
+ const selected = findBestOption(req.accepts, signers, preferredScheme);
7251
+ if (!selected) {
7252
+ throw new Error("No compatible payment option found for available signers");
7253
+ }
7254
+ if (options?.spendingLimit !== void 0) {
7255
+ const amount = BigInt(selected.amount);
7256
+ if (amount > options.spendingLimit) {
7257
+ throw new Error(`Payment amount ${amount} exceeds spending limit ${options.spendingLimit}`);
7258
+ }
7259
+ }
7260
+ if (options?.onApprovalRequired) {
7261
+ const approved = await options.onApprovalRequired({
7262
+ amount: BigInt(selected.amount),
7263
+ network: selected.network
7264
+ });
7265
+ if (!approved) {
7266
+ throw new Error("Payment rejected by approval callback");
7267
+ }
7268
+ }
7269
+ const signerEntry = signers.find((s) => s.network === selected.network && s.scheme === selected.scheme) ?? signers.find((s) => s.network === selected.network);
7270
+ if (!signerEntry) {
7271
+ throw new Error(`No signer available for network ${selected.network}`);
7272
+ }
7273
+ if (options?.autoBalance) {
7274
+ const chainName = getChainNameFromNetwork(wdk, selected.network);
7275
+ if (chainName) {
7276
+ const balance = await wdk.getUsdt0Balance(chainName);
7277
+ const requiredAmount = BigInt(selected.amount);
7278
+ if (balance < requiredAmount && options.autoBridge) {
7279
+ const best = await wdk.findBestChainForPayment(requiredAmount);
7280
+ if (best && best.chain !== chainName) {
7281
+ await wdk.bridgeUsdt0({
7282
+ fromChain: best.chain,
7283
+ toChain: chainName,
7284
+ amount: requiredAmount
7285
+ });
7286
+ }
7287
+ }
7288
+ }
7289
+ }
7290
+ const signer = signerEntry.signer;
7291
+ const now = Math.floor(Date.now() / 1e3);
7292
+ const deadline = now + selected.maxTimeoutSeconds;
7293
+ const nonce = "0x" + Array.from(globalThis.crypto.getRandomValues(new Uint8Array(32))).map((b) => b.toString(16).padStart(2, "0")).join("");
7294
+ const chainId = parseInt(selected.network.split(":")[1] || "0");
7295
+ const signature = await signer.signTypedData({
7296
+ domain: {
7297
+ name: "USD\u20AE0",
7298
+ version: "1",
7299
+ chainId,
7300
+ verifyingContract: selected.asset
7301
+ },
7302
+ types: {
7303
+ TransferWithAuthorization: [
7304
+ { name: "from", type: "address" },
7305
+ { name: "to", type: "address" },
7306
+ { name: "value", type: "uint256" },
7307
+ { name: "validAfter", type: "uint256" },
7308
+ { name: "validBefore", type: "uint256" },
7309
+ { name: "nonce", type: "bytes32" }
7310
+ ]
7311
+ },
7312
+ primaryType: "TransferWithAuthorization",
7313
+ message: {
7314
+ from: signer.address,
7315
+ to: selected.payTo,
7316
+ value: BigInt(selected.amount),
7317
+ validAfter: 0n,
7318
+ validBefore: BigInt(deadline),
7319
+ nonce
7320
+ }
7321
+ });
7322
+ return {
7323
+ t402Version: req.t402Version,
7324
+ resource: req.resource,
7325
+ accepted: selected,
7326
+ payload: {
7327
+ signature,
7328
+ from: signer.address,
7329
+ validAfter: "0",
7330
+ validBefore: deadline.toString(),
7331
+ nonce
7332
+ }
7333
+ };
7334
+ };
7335
+ return { signers, paymentHandler };
7336
+ }
7337
+ function getChainNameFromNetwork(wdk, network) {
7338
+ for (const chain of wdk.getConfiguredChains()) {
7339
+ const config = wdk.getChainConfig(chain);
7340
+ if (config && config.network === network) {
7341
+ return chain;
7342
+ }
7343
+ }
7344
+ return void 0;
7345
+ }
7346
+
7347
+ // src/integrations/facilitator-adapter.ts
7348
+ async function toFacilitatorWdkSigner(wdk, chain, options) {
7349
+ const wdkSigner = await wdk.getSigner(chain);
7350
+ const address = wdkSigner.address;
7351
+ return {
7352
+ address,
7353
+ async signTransaction(tx) {
7354
+ if (tx && typeof tx === "object" && "domain" in tx) {
7355
+ const typedData = tx;
7356
+ return wdkSigner.signTypedData(typedData);
7357
+ }
7358
+ if (typeof tx === "string") {
7359
+ return wdkSigner.signMessage(tx);
7360
+ }
7361
+ throw new Error("Unsupported transaction format for WDK facilitator signer");
7362
+ },
7363
+ async signTypedData(data) {
7364
+ return wdkSigner.signTypedData(data);
7365
+ },
7366
+ async sendTransaction(params) {
7367
+ const result = await wdkSigner.sendTransaction({
7368
+ to: params.to,
7369
+ value: params.value,
7370
+ data: params.data
7371
+ });
7372
+ if (options?.bridgeToMainChain && options.bridgeToMainChain !== chain) {
7373
+ const balance = await wdk.getUsdt0Balance(chain);
7374
+ if (balance > 0n) {
7375
+ try {
7376
+ await wdk.bridgeUsdt0({
7377
+ fromChain: chain,
7378
+ toChain: options.bridgeToMainChain,
7379
+ amount: balance
7380
+ });
7381
+ } catch {
7382
+ }
7383
+ }
7384
+ }
7385
+ return result.hash;
7386
+ }
7387
+ };
7388
+ }
7389
+ async function createFacilitatorSigners(wdk, options) {
7390
+ const chains = wdk.getConfiguredChains();
7391
+ const signers = /* @__PURE__ */ new Map();
7392
+ const results = await Promise.allSettled(
7393
+ chains.map(async (chain) => {
7394
+ const signer = await toFacilitatorWdkSigner(wdk, chain, options);
7395
+ return { chain, signer };
7396
+ })
7397
+ );
7398
+ for (const result of results) {
7399
+ if (result.status === "fulfilled") {
7400
+ signers.set(result.value.chain, result.value.signer);
7401
+ }
7402
+ }
7403
+ return signers;
7404
+ }
7405
+
7406
+ // src/integrations/siwx-adapter.ts
7407
+ async function toSIWxSigner(wdk, chain) {
7408
+ const wdkSigner = await wdk.getSigner(chain);
7409
+ return {
7410
+ address: wdkSigner.address,
7411
+ async signMessage(message) {
7412
+ return wdkSigner.signMessage(message);
7413
+ },
7414
+ async signTypedData(data) {
7415
+ return wdkSigner.signTypedData({
7416
+ domain: data.domain,
7417
+ types: data.types,
7418
+ primaryType: data.primaryType,
7419
+ message: data.message
7420
+ });
7421
+ }
7422
+ };
7423
+ }
7424
+ async function createSIWxSigners(wdk) {
7425
+ const chains = wdk.getConfiguredChains();
7426
+ const signers = /* @__PURE__ */ new Map();
7427
+ const results = await Promise.allSettled(
7428
+ chains.map(async (chain) => {
7429
+ const signer = await toSIWxSigner(wdk, chain);
7430
+ return { chain, signer };
7431
+ })
7432
+ );
7433
+ for (const result of results) {
7434
+ if (result.status === "fulfilled") {
7435
+ signers.set(result.value.chain, result.value.signer);
7436
+ }
7437
+ }
7438
+ return signers;
7439
+ }
3837
7440
  // Annotate the CommonJS export names for ESM import in node:
3838
7441
  0 && (module.exports = {
7442
+ AmountLimitProvider,
3839
7443
  BalanceCache,
3840
7444
  BalanceError,
7445
+ BlacklistProvider,
3841
7446
  BridgeError,
7447
+ BridgeTracker,
7448
+ CHAIN_REGISTRY,
3842
7449
  CHAIN_TOKENS,
3843
7450
  ChainError,
7451
+ ComplianceManager,
3844
7452
  DEFAULT_BALANCE_CACHE_CONFIG,
3845
7453
  DEFAULT_CACHE_CONFIG,
3846
7454
  DEFAULT_CHAINS,
3847
7455
  DEFAULT_RETRY_CONFIG,
3848
7456
  DEFAULT_RPC_ENDPOINTS,
7457
+ FailoverProvider,
3849
7458
  HardwareWalletError,
3850
7459
  HardwareWalletErrorCode,
7460
+ InMemoryIdempotencyManager,
7461
+ InMemoryReceiptStore,
3851
7462
  LAYERZERO_ENDPOINT_IDS,
3852
7463
  LedgerSigner,
3853
7464
  MockWDKSigner,
7465
+ MoonpayOnRampProvider,
7466
+ NonceManager,
3854
7467
  RPCError,
7468
+ SUPPORTED_WDK_RANGE,
3855
7469
  SignerError,
3856
7470
  SigningError,
7471
+ T402EventEmitter,
3857
7472
  T402WDK,
3858
7473
  TTLCache,
3859
7474
  TransactionError,
@@ -3872,28 +7487,72 @@ function isHardwareWalletSupported() {
3872
7487
  WDKTronSignerAdapter,
3873
7488
  WDK_COMPATIBILITY,
3874
7489
  WdkBridge,
7490
+ WdkIndexerVerifier,
7491
+ WebhookManager,
7492
+ buildVersionedTransaction,
3875
7493
  checkWalletEvmCompatibility,
3876
7494
  checkWdkCompatibility,
7495
+ compareSemver,
7496
+ createBackup,
7497
+ createCorrelationId,
3877
7498
  createDirectBridge,
7499
+ createFacilitatorSigners,
7500
+ createFailoverProvider,
7501
+ createIndexerVerifier,
3878
7502
  createLedgerSigner,
7503
+ createSIWxSigners,
3879
7504
  createTrezorSigner,
3880
7505
  createWDKSigner,
3881
7506
  createWDKSvmSigner,
3882
7507
  createWDKTonSigner,
3883
7508
  createWDKTronSigner,
7509
+ createWdkA2APaymentClient,
7510
+ createWdkMoneyParser,
7511
+ decryptSeed,
7512
+ defaultLogger,
7513
+ deriveATAAddress,
3884
7514
  detectHardwareWalletSupport,
7515
+ encryptSeed,
7516
+ generateIdempotencyKey,
3885
7517
  getBridgeableChains,
3886
7518
  getChainFromNetwork,
3887
7519
  getChainId,
7520
+ getChainsByFamily,
7521
+ getJettonWalletAddress,
7522
+ getMoonpayCurrencyCode,
3888
7523
  getNetworkFromChain,
3889
7524
  getPreferredToken,
7525
+ getPricingProvider,
7526
+ getRecentPriorityFees,
7527
+ getRegistryByCaip2,
7528
+ getSecretManager,
7529
+ getTokenProgram,
7530
+ getTransferFee,
3890
7531
  getUsdt0Chains,
3891
7532
  getWalletModuleMinVersion,
3892
7533
  hasErrorCode,
3893
7534
  isHardwareWalletSupported,
7535
+ isPricingProviderRegistered,
3894
7536
  isWDKError,
7537
+ mapLayerZeroStatus,
7538
+ noopLogger,
3895
7539
  normalizeChainConfig,
7540
+ parseSemver,
7541
+ registerPricingProvider,
7542
+ registerSecretManager,
7543
+ resolveATA,
7544
+ resolveAssetForNetwork,
7545
+ resolveRpcUrl,
7546
+ rotateSeedPassword,
7547
+ satisfiesSemverRange,
3896
7548
  supportsBridging,
7549
+ toAtomicUnits,
7550
+ toFacilitatorWdkSigner,
7551
+ toSIWxSigner,
7552
+ transferWithPriorityFee,
7553
+ validatePaymentAddress,
7554
+ verifyBackup,
7555
+ waitForJettonTransfer,
3897
7556
  withRetry,
3898
7557
  withTimeout,
3899
7558
  wrapError