@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
@@ -1,15 +1,296 @@
1
+ import {
2
+ createWDKBtcSigner,
3
+ createWDKSparkSigner
4
+ } from "./chunk-7CG77QAN.mjs";
1
5
  import {
2
6
  WDKSvmSignerAdapter,
3
- createWDKSvmSigner
4
- } from "./chunk-MCFHZSF7.mjs";
7
+ buildVersionedTransaction,
8
+ createWDKSvmSigner,
9
+ deriveATAAddress,
10
+ getRecentPriorityFees,
11
+ getTokenProgram,
12
+ getTransferFee,
13
+ resolveATA,
14
+ transferWithPriorityFee
15
+ } from "./chunk-2KWVW77U.mjs";
5
16
  import {
6
17
  WDKTonSignerAdapter,
7
- createWDKTonSigner
8
- } from "./chunk-YWBJJV5M.mjs";
18
+ createWDKTonSigner,
19
+ getJettonWalletAddress,
20
+ waitForJettonTransfer
21
+ } from "./chunk-KWX6CJIH.mjs";
9
22
  import {
10
23
  WDKTronSignerAdapter,
11
24
  createWDKTronSigner
12
- } from "./chunk-HB2DGKQ3.mjs";
25
+ } from "./chunk-QZKUU2O6.mjs";
26
+ import {
27
+ createFacilitatorSigners,
28
+ createSIWxSigners,
29
+ createWdkA2APaymentClient,
30
+ toFacilitatorWdkSigner,
31
+ toSIWxSigner
32
+ } from "./chunk-TVSNUSFZ.mjs";
33
+ import {
34
+ __require
35
+ } from "./chunk-BJTO5JO5.mjs";
36
+
37
+ // src/secret.ts
38
+ var _secretManager = null;
39
+ async function encryptSeed(seedPhrase, password) {
40
+ if (!seedPhrase || typeof seedPhrase !== "string") {
41
+ throw new Error("Seed phrase is required and must be a string");
42
+ }
43
+ if (!password || typeof password !== "string") {
44
+ throw new Error("Password is required and must be a string");
45
+ }
46
+ const crypto = await import("crypto");
47
+ const salt = crypto.randomBytes(32);
48
+ const iv = crypto.randomBytes(16);
49
+ const key = crypto.pbkdf2Sync(password, salt, 1e5, 32, "sha256");
50
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
51
+ const encrypted = Buffer.concat([cipher.update(seedPhrase, "utf8"), cipher.final()]);
52
+ const authTag = cipher.getAuthTag();
53
+ return {
54
+ ciphertext: Buffer.concat([encrypted, authTag]).toString("base64"),
55
+ algorithm: "aes-256-gcm",
56
+ kdf: {
57
+ salt: salt.toString("base64"),
58
+ iterations: 1e5,
59
+ keyLength: 32,
60
+ hash: "sha256"
61
+ },
62
+ iv: iv.toString("base64"),
63
+ version: 1
64
+ };
65
+ }
66
+ async function decryptSeed(encrypted, password) {
67
+ if (!encrypted || typeof encrypted !== "object") {
68
+ throw new Error("Encrypted seed data is required");
69
+ }
70
+ if (!password || typeof password !== "string") {
71
+ throw new Error("Password is required and must be a string");
72
+ }
73
+ const crypto = await import("crypto");
74
+ const salt = Buffer.from(encrypted.kdf.salt, "base64");
75
+ const iv = Buffer.from(encrypted.iv, "base64");
76
+ const key = crypto.pbkdf2Sync(
77
+ password,
78
+ salt,
79
+ encrypted.kdf.iterations,
80
+ encrypted.kdf.keyLength,
81
+ encrypted.kdf.hash
82
+ );
83
+ const data = Buffer.from(encrypted.ciphertext, "base64");
84
+ const authTag = data.subarray(-16);
85
+ const ciphertext = data.subarray(0, -16);
86
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
87
+ decipher.setAuthTag(authTag);
88
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
89
+ }
90
+ async function rotateSeedPassword(encrypted, oldPassword, newPassword, options) {
91
+ if (!newPassword || typeof newPassword !== "string") {
92
+ throw new Error("New password is required and must be a string");
93
+ }
94
+ const manager = getSecretManager();
95
+ const seedPhrase = await manager.decrypt(encrypted, oldPassword);
96
+ const iterations = options?.iterations ?? encrypted.kdf.iterations;
97
+ const newVersion = options?.iterations && options.iterations !== encrypted.kdf.iterations ? 2 : encrypted.version;
98
+ const crypto = await import("crypto");
99
+ const salt = crypto.randomBytes(32);
100
+ const iv = crypto.randomBytes(16);
101
+ const key = crypto.pbkdf2Sync(newPassword, salt, iterations, 32, "sha256");
102
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
103
+ const encryptedData = Buffer.concat([cipher.update(seedPhrase, "utf8"), cipher.final()]);
104
+ const authTag = cipher.getAuthTag();
105
+ return {
106
+ ciphertext: Buffer.concat([encryptedData, authTag]).toString("base64"),
107
+ algorithm: "aes-256-gcm",
108
+ kdf: {
109
+ salt: salt.toString("base64"),
110
+ iterations,
111
+ keyLength: 32,
112
+ hash: "sha256"
113
+ },
114
+ iv: iv.toString("base64"),
115
+ version: newVersion
116
+ };
117
+ }
118
+ function registerSecretManager(manager) {
119
+ _secretManager = manager;
120
+ }
121
+ function getSecretManager() {
122
+ if (_secretManager) {
123
+ return _secretManager;
124
+ }
125
+ return {
126
+ encrypt: encryptSeed,
127
+ decrypt: decryptSeed
128
+ };
129
+ }
130
+ async function createBackup(seedPhrase, password, metadata) {
131
+ if (!seedPhrase || typeof seedPhrase !== "string") {
132
+ throw new Error("Seed phrase is required and must be a string");
133
+ }
134
+ if (!password || typeof password !== "string") {
135
+ throw new Error("Password is required and must be a string");
136
+ }
137
+ const manager = getSecretManager();
138
+ const encrypted = await manager.encrypt(seedPhrase, password);
139
+ const envelope = {
140
+ encrypted,
141
+ metadata
142
+ };
143
+ return JSON.stringify(envelope, null, 2);
144
+ }
145
+ async function verifyBackup(backup, password, expectedAddresses) {
146
+ let envelope;
147
+ try {
148
+ envelope = JSON.parse(backup);
149
+ } catch {
150
+ return { valid: false, addressMatch: false };
151
+ }
152
+ if (!envelope.encrypted || !envelope.metadata) {
153
+ return { valid: false, addressMatch: false };
154
+ }
155
+ try {
156
+ const manager = getSecretManager();
157
+ await manager.decrypt(envelope.encrypted, password);
158
+ } catch {
159
+ return { valid: false, addressMatch: false };
160
+ }
161
+ let addressMatch = true;
162
+ if (expectedAddresses && envelope.metadata.addressHints) {
163
+ for (const [chain, expectedAddr] of Object.entries(expectedAddresses)) {
164
+ const hint = envelope.metadata.addressHints[chain];
165
+ if (hint && hint.toLowerCase() !== expectedAddr.toLowerCase()) {
166
+ addressMatch = false;
167
+ break;
168
+ }
169
+ }
170
+ }
171
+ return { valid: true, addressMatch, metadata: envelope.metadata };
172
+ }
173
+
174
+ // src/events.ts
175
+ var T402EventEmitter = class {
176
+ handlers = /* @__PURE__ */ new Map();
177
+ on(event, handler) {
178
+ let set = this.handlers.get(event);
179
+ if (!set) {
180
+ set = /* @__PURE__ */ new Set();
181
+ this.handlers.set(event, set);
182
+ }
183
+ set.add(handler);
184
+ return this;
185
+ }
186
+ off(event, handler) {
187
+ const set = this.handlers.get(event);
188
+ if (set) {
189
+ set.delete(handler);
190
+ if (set.size === 0) {
191
+ this.handlers.delete(event);
192
+ }
193
+ }
194
+ return this;
195
+ }
196
+ once(event, handler) {
197
+ const wrapper = (data) => {
198
+ this.off(event, wrapper);
199
+ handler(data);
200
+ };
201
+ return this.on(event, wrapper);
202
+ }
203
+ emit(event, data) {
204
+ const set = this.handlers.get(event);
205
+ if (!set || set.size === 0) {
206
+ return false;
207
+ }
208
+ for (const handler of set) {
209
+ handler(data);
210
+ }
211
+ return true;
212
+ }
213
+ removeAllListeners(event) {
214
+ if (event) {
215
+ this.handlers.delete(event);
216
+ } else {
217
+ this.handlers.clear();
218
+ }
219
+ return this;
220
+ }
221
+ listenerCount(event) {
222
+ return this.handlers.get(event)?.size ?? 0;
223
+ }
224
+ };
225
+
226
+ // src/receipts.ts
227
+ var InMemoryReceiptStore = class {
228
+ receipts = /* @__PURE__ */ new Map();
229
+ async save(receipt) {
230
+ this.receipts.set(receipt.id, receipt);
231
+ }
232
+ async getById(id) {
233
+ return this.receipts.get(id) ?? null;
234
+ }
235
+ async query(filter) {
236
+ let results = Array.from(this.receipts.values());
237
+ results = applyFilter(results, filter);
238
+ return results;
239
+ }
240
+ async getAll() {
241
+ return Array.from(this.receipts.values());
242
+ }
243
+ async count(filter) {
244
+ if (!filter) {
245
+ return this.receipts.size;
246
+ }
247
+ const filtered = applyFilter(Array.from(this.receipts.values()), filter);
248
+ return filtered.length;
249
+ }
250
+ async clear() {
251
+ this.receipts.clear();
252
+ }
253
+ async exportJSON() {
254
+ return JSON.stringify(Array.from(this.receipts.values()), null, 2);
255
+ }
256
+ };
257
+ function applyFilter(receipts, filter) {
258
+ if (!filter) return receipts;
259
+ let results = receipts;
260
+ if (filter.network !== void 0) {
261
+ results = results.filter((r) => r.network === filter.network);
262
+ }
263
+ if (filter.chainFamily !== void 0) {
264
+ results = results.filter((r) => r.chainFamily === filter.chainFamily);
265
+ }
266
+ if (filter.success !== void 0) {
267
+ results = results.filter((r) => r.success === filter.success);
268
+ }
269
+ if (filter.fromDate !== void 0) {
270
+ const from = filter.fromDate;
271
+ results = results.filter((r) => r.timestamp >= from);
272
+ }
273
+ if (filter.toDate !== void 0) {
274
+ const to = filter.toDate;
275
+ results = results.filter((r) => r.timestamp <= to);
276
+ }
277
+ if (filter.minAmount !== void 0) {
278
+ const min = BigInt(filter.minAmount);
279
+ results = results.filter((r) => BigInt(r.amount) >= min);
280
+ }
281
+ if (filter.maxAmount !== void 0) {
282
+ const max = BigInt(filter.maxAmount);
283
+ results = results.filter((r) => BigInt(r.amount) <= max);
284
+ }
285
+ results.sort((a, b) => a.timestamp > b.timestamp ? -1 : a.timestamp < b.timestamp ? 1 : 0);
286
+ if (filter.offset !== void 0 && filter.offset > 0) {
287
+ results = results.slice(filter.offset);
288
+ }
289
+ if (filter.limit !== void 0 && filter.limit > 0) {
290
+ results = results.slice(0, filter.limit);
291
+ }
292
+ return results;
293
+ }
13
294
 
14
295
  // src/cache.ts
15
296
  var DEFAULT_CACHE_CONFIG = {
@@ -629,6 +910,145 @@ var CHAIN_TOKENS = {
629
910
  }
630
911
  ]
631
912
  };
913
+ var CHAIN_REGISTRY = {
914
+ // --- EVM chains (derived from existing constants) ---
915
+ ethereum: {
916
+ family: "evm",
917
+ chainId: 1,
918
+ caip2: "eip155:1",
919
+ rpcEndpoints: ["https://eth.drpc.org"],
920
+ tokens: (CHAIN_TOKENS.ethereum ?? []).map((t) => ({
921
+ address: t.address,
922
+ symbol: t.symbol,
923
+ decimals: t.decimals
924
+ }))
925
+ },
926
+ arbitrum: {
927
+ family: "evm",
928
+ chainId: 42161,
929
+ caip2: "eip155:42161",
930
+ rpcEndpoints: ["https://arb1.arbitrum.io/rpc"],
931
+ tokens: (CHAIN_TOKENS.arbitrum ?? []).map((t) => ({
932
+ address: t.address,
933
+ symbol: t.symbol,
934
+ decimals: t.decimals
935
+ }))
936
+ },
937
+ base: {
938
+ family: "evm",
939
+ chainId: 8453,
940
+ caip2: "eip155:8453",
941
+ rpcEndpoints: ["https://mainnet.base.org"],
942
+ tokens: (CHAIN_TOKENS.base ?? []).map((t) => ({
943
+ address: t.address,
944
+ symbol: t.symbol,
945
+ decimals: t.decimals
946
+ }))
947
+ },
948
+ ink: {
949
+ family: "evm",
950
+ chainId: 57073,
951
+ caip2: "eip155:57073",
952
+ rpcEndpoints: ["https://rpc-gel.inkonchain.com"],
953
+ tokens: (CHAIN_TOKENS.ink ?? []).map((t) => ({
954
+ address: t.address,
955
+ symbol: t.symbol,
956
+ decimals: t.decimals
957
+ }))
958
+ },
959
+ berachain: {
960
+ family: "evm",
961
+ chainId: 80094,
962
+ caip2: "eip155:80094",
963
+ rpcEndpoints: [],
964
+ tokens: (CHAIN_TOKENS.berachain ?? []).map((t) => ({
965
+ address: t.address,
966
+ symbol: t.symbol,
967
+ decimals: t.decimals
968
+ }))
969
+ },
970
+ unichain: {
971
+ family: "evm",
972
+ chainId: 130,
973
+ caip2: "eip155:130",
974
+ rpcEndpoints: [],
975
+ tokens: (CHAIN_TOKENS.unichain ?? []).map((t) => ({
976
+ address: t.address,
977
+ symbol: t.symbol,
978
+ decimals: t.decimals
979
+ }))
980
+ },
981
+ optimism: {
982
+ family: "evm",
983
+ chainId: 10,
984
+ caip2: "eip155:10",
985
+ rpcEndpoints: ["https://mainnet.optimism.io"],
986
+ tokens: (CHAIN_TOKENS.optimism ?? []).map((t) => ({
987
+ address: t.address,
988
+ symbol: t.symbol,
989
+ decimals: t.decimals
990
+ }))
991
+ },
992
+ polygon: {
993
+ family: "evm",
994
+ chainId: 137,
995
+ caip2: "eip155:137",
996
+ rpcEndpoints: ["https://polygon-rpc.com"],
997
+ tokens: (CHAIN_TOKENS.polygon ?? []).map((t) => ({
998
+ address: t.address,
999
+ symbol: t.symbol,
1000
+ decimals: t.decimals
1001
+ }))
1002
+ },
1003
+ // --- Non-EVM chains ---
1004
+ ton: {
1005
+ family: "ton",
1006
+ caip2: "ton:mainnet",
1007
+ rpcEndpoints: ["https://toncenter.com/api/v2/jsonRPC"],
1008
+ tokens: [
1009
+ {
1010
+ address: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
1011
+ symbol: "USDT",
1012
+ decimals: 6
1013
+ }
1014
+ ]
1015
+ },
1016
+ tron: {
1017
+ family: "tron",
1018
+ caip2: "tron:mainnet",
1019
+ rpcEndpoints: ["https://api.trongrid.io"],
1020
+ tokens: [
1021
+ {
1022
+ address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
1023
+ symbol: "USDT",
1024
+ decimals: 6
1025
+ }
1026
+ ]
1027
+ },
1028
+ solana: {
1029
+ family: "svm",
1030
+ caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
1031
+ rpcEndpoints: ["https://api.mainnet-beta.solana.com"],
1032
+ tokens: [
1033
+ {
1034
+ address: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
1035
+ symbol: "USDT",
1036
+ decimals: 6
1037
+ }
1038
+ ]
1039
+ }
1040
+ };
1041
+ function getRegistryByCaip2(caip2) {
1042
+ for (const entry of Object.values(CHAIN_REGISTRY)) {
1043
+ if (entry.caip2 === caip2) {
1044
+ return entry;
1045
+ }
1046
+ }
1047
+ return void 0;
1048
+ }
1049
+ function getChainsByFamily(family) {
1050
+ return Object.entries(CHAIN_REGISTRY).filter(([, entry]) => entry.family === family).map(([name]) => name);
1051
+ }
632
1052
  function normalizeChainConfig(chainName, config) {
633
1053
  const defaultConfig = DEFAULT_CHAINS[chainName];
634
1054
  if (typeof config === "string") {
@@ -639,8 +1059,9 @@ function normalizeChainConfig(chainName, config) {
639
1059
  name: chainName
640
1060
  };
641
1061
  }
1062
+ const resolvedProvider = Array.isArray(config.provider) ? config.provider[0] : config.provider;
642
1063
  return {
643
- provider: config.provider,
1064
+ provider: resolvedProvider,
644
1065
  chainId: config.chainId ?? defaultConfig?.chainId ?? 1,
645
1066
  network: config.network ?? defaultConfig?.network ?? `eip155:${config.chainId}`,
646
1067
  name: chainName
@@ -655,6 +1076,11 @@ function getChainFromNetwork(network) {
655
1076
  return chain;
656
1077
  }
657
1078
  }
1079
+ for (const [chain, entry] of Object.entries(CHAIN_REGISTRY)) {
1080
+ if (entry.caip2 === network) {
1081
+ return chain;
1082
+ }
1083
+ }
658
1084
  return void 0;
659
1085
  }
660
1086
  function getChainId(chain) {
@@ -1317,6 +1743,65 @@ var WDKSigner = class {
1317
1743
  );
1318
1744
  }
1319
1745
  }
1746
+ /**
1747
+ * Sign an EIP-2612 permit for gasless token approvals
1748
+ *
1749
+ * @param params - Permit parameters
1750
+ * @returns The permit signature components (v, r, s)
1751
+ * @throws {SigningError} If signing fails
1752
+ */
1753
+ async signPermit(params) {
1754
+ if (!params.token || !params.token.startsWith("0x")) {
1755
+ throw new SigningError(
1756
+ 4003 /* INVALID_TYPED_DATA */,
1757
+ `Invalid token address: ${params.token}`,
1758
+ { operation: "signTypedData", context: { chain: this._chain } }
1759
+ );
1760
+ }
1761
+ if (!params.spender || !params.spender.startsWith("0x")) {
1762
+ throw new SigningError(
1763
+ 4003 /* INVALID_TYPED_DATA */,
1764
+ `Invalid spender address: ${params.spender}`,
1765
+ { operation: "signTypedData", context: { chain: this._chain } }
1766
+ );
1767
+ }
1768
+ const chainId = this.getChainId();
1769
+ const nonce = params.nonce ?? 0n;
1770
+ const typedData = {
1771
+ domain: {
1772
+ name: params.tokenName ?? "Tether USD",
1773
+ version: params.tokenVersion ?? "1",
1774
+ chainId: BigInt(chainId),
1775
+ verifyingContract: params.token
1776
+ },
1777
+ types: {
1778
+ Permit: [
1779
+ { name: "owner", type: "address" },
1780
+ { name: "spender", type: "address" },
1781
+ { name: "value", type: "uint256" },
1782
+ { name: "nonce", type: "uint256" },
1783
+ { name: "deadline", type: "uint256" }
1784
+ ]
1785
+ },
1786
+ primaryType: "Permit",
1787
+ message: {
1788
+ owner: this.address,
1789
+ spender: params.spender,
1790
+ value: params.value.toString(),
1791
+ nonce: nonce.toString(),
1792
+ deadline: params.deadline.toString()
1793
+ }
1794
+ };
1795
+ const signature = await this.signTypedData(typedData);
1796
+ const sigHex = signature.slice(2);
1797
+ const r = `0x${sigHex.slice(0, 64)}`;
1798
+ const s = `0x${sigHex.slice(64, 128)}`;
1799
+ let v = parseInt(sigHex.slice(128, 130), 16);
1800
+ if (v < 27) {
1801
+ v += 27;
1802
+ }
1803
+ return { v, r, s };
1804
+ }
1320
1805
  /**
1321
1806
  * Send a transaction (for advanced use cases)
1322
1807
  *
@@ -1387,6 +1872,311 @@ var MockWDKSigner = class {
1387
1872
 
1388
1873
  // src/t402wdk.ts
1389
1874
  import { supportsBridging, getBridgeableChains } from "@t402/evm";
1875
+
1876
+ // src/pricing.ts
1877
+ var _registeredPricingProvider = null;
1878
+ function registerPricingProvider(provider) {
1879
+ _registeredPricingProvider = provider;
1880
+ }
1881
+ function getPricingProvider() {
1882
+ return _registeredPricingProvider;
1883
+ }
1884
+ function isPricingProviderRegistered() {
1885
+ return _registeredPricingProvider !== null;
1886
+ }
1887
+ var STABLECOIN_SYMBOLS = /* @__PURE__ */ new Set(["USDT", "USDT0", "USDC", "DAI", "BUSD"]);
1888
+ var DEFAULT_TTL = 6e4;
1889
+ var DEFAULT_FIAT = ["USD", "EUR", "GBP", "JPY"];
1890
+ function createWdkMoneyParser(config) {
1891
+ const cacheTTL = config?.cacheTTL ?? DEFAULT_TTL;
1892
+ const supportedFiat = new Set(config?.supportedFiat ?? DEFAULT_FIAT);
1893
+ const cache = /* @__PURE__ */ new Map();
1894
+ return async (amount, network) => {
1895
+ if (!Number.isFinite(amount) || amount <= 0) return null;
1896
+ const chain = getChainFromNetwork(network);
1897
+ if (!chain) return null;
1898
+ const tokenInfo = getPreferredToken(chain);
1899
+ if (!tokenInfo) return null;
1900
+ if (STABLECOIN_SYMBOLS.has(tokenInfo.symbol.toUpperCase())) {
1901
+ return {
1902
+ amount: toAtomicUnits(amount, tokenInfo.decimals),
1903
+ asset: tokenInfo.address
1904
+ };
1905
+ }
1906
+ const currency = "USD";
1907
+ if (!supportedFiat.has(currency)) return null;
1908
+ const cacheKey = `${currency}_${tokenInfo.symbol}`;
1909
+ const cached = cache.get(cacheKey);
1910
+ const now = Date.now();
1911
+ let rate;
1912
+ if (cached && now - cached.fetchedAt < cacheTTL) {
1913
+ rate = cached.rate;
1914
+ } else {
1915
+ rate = await fetchRate(currency, tokenInfo.symbol);
1916
+ cache.set(cacheKey, { rate, fetchedAt: now });
1917
+ }
1918
+ const convertedAmount = amount * rate;
1919
+ return {
1920
+ amount: toAtomicUnits(convertedAmount, tokenInfo.decimals),
1921
+ asset: tokenInfo.address
1922
+ };
1923
+ };
1924
+ }
1925
+ function toAtomicUnits(amount, decimals) {
1926
+ const factor = 10 ** decimals;
1927
+ const atomic = Math.round(amount * factor);
1928
+ return atomic.toString();
1929
+ }
1930
+ function resolveAssetForNetwork(token, network) {
1931
+ const chain = getChainFromNetwork(network);
1932
+ if (!chain) return null;
1933
+ const upper = token.toUpperCase();
1934
+ if (upper === "USDT0" || upper === "USDT") {
1935
+ return USDT0_ADDRESSES[chain] ?? null;
1936
+ }
1937
+ if (upper === "USDC") {
1938
+ return USDC_ADDRESSES[chain] ?? null;
1939
+ }
1940
+ return null;
1941
+ }
1942
+ async function fetchRate(fromCurrency, toToken) {
1943
+ if (_registeredPricingProvider) {
1944
+ try {
1945
+ return await _registeredPricingProvider.getRate(fromCurrency, toToken);
1946
+ } catch {
1947
+ }
1948
+ }
1949
+ if (fromCurrency.toUpperCase() === "USD") {
1950
+ return 1;
1951
+ }
1952
+ const placeholderRates = {
1953
+ EUR: 1.08,
1954
+ GBP: 1.27,
1955
+ JPY: 67e-4
1956
+ };
1957
+ return placeholderRates[fromCurrency.toUpperCase()] ?? 1;
1958
+ }
1959
+
1960
+ // src/failover.ts
1961
+ var DEFAULT_HEALTH_CHECK_INTERVAL = 3e4;
1962
+ var DEFAULT_REQUEST_TIMEOUT = 5e3;
1963
+ var DEFAULT_MAX_FAILURES = 3;
1964
+ var FailoverProvider = class {
1965
+ providers;
1966
+ currentIndex = 0;
1967
+ healthCheckTimer;
1968
+ maxFailures;
1969
+ requestTimeout;
1970
+ constructor(config) {
1971
+ if (!config.urls || config.urls.length === 0) {
1972
+ throw new Error("FailoverProvider requires at least one URL");
1973
+ }
1974
+ this.maxFailures = config.maxFailures ?? DEFAULT_MAX_FAILURES;
1975
+ this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
1976
+ this.providers = config.urls.map((url) => ({
1977
+ url,
1978
+ healthy: true,
1979
+ lastChecked: Date.now(),
1980
+ consecutiveFailures: 0
1981
+ }));
1982
+ const interval = config.healthCheckInterval ?? DEFAULT_HEALTH_CHECK_INTERVAL;
1983
+ if (interval > 0) {
1984
+ this.startHealthChecks(interval);
1985
+ }
1986
+ }
1987
+ /**
1988
+ * Get current active RPC URL
1989
+ */
1990
+ getCurrentUrl() {
1991
+ return this.providers[this.currentIndex].url;
1992
+ }
1993
+ /**
1994
+ * Report a failure on the current URL.
1995
+ * Auto-switches to next healthy provider if failure threshold is reached.
1996
+ *
1997
+ * @returns The new URL if switched, or null if no switch occurred
1998
+ */
1999
+ reportFailure() {
2000
+ const provider = this.providers[this.currentIndex];
2001
+ provider.consecutiveFailures++;
2002
+ provider.lastChecked = Date.now();
2003
+ if (provider.consecutiveFailures >= this.maxFailures) {
2004
+ provider.healthy = false;
2005
+ return this.switchToNext();
2006
+ }
2007
+ return null;
2008
+ }
2009
+ /**
2010
+ * Report success on the current URL, reset failure counter.
2011
+ */
2012
+ reportSuccess() {
2013
+ const provider = this.providers[this.currentIndex];
2014
+ provider.consecutiveFailures = 0;
2015
+ provider.healthy = true;
2016
+ provider.lastChecked = Date.now();
2017
+ }
2018
+ /**
2019
+ * Get all provider statuses
2020
+ */
2021
+ getStatus() {
2022
+ return this.providers.map((p) => ({ ...p }));
2023
+ }
2024
+ /**
2025
+ * Force switch to next healthy provider.
2026
+ *
2027
+ * @returns The new URL, or null if no healthy providers available
2028
+ */
2029
+ switchToNext() {
2030
+ const startIndex = this.currentIndex;
2031
+ for (let i = 1; i <= this.providers.length; i++) {
2032
+ const nextIndex = (startIndex + i) % this.providers.length;
2033
+ if (this.providers[nextIndex].healthy) {
2034
+ this.currentIndex = nextIndex;
2035
+ return this.providers[nextIndex].url;
2036
+ }
2037
+ }
2038
+ return null;
2039
+ }
2040
+ /**
2041
+ * Get the request timeout in milliseconds
2042
+ */
2043
+ getRequestTimeout() {
2044
+ return this.requestTimeout;
2045
+ }
2046
+ /**
2047
+ * Stop health checks and clean up resources
2048
+ */
2049
+ dispose() {
2050
+ if (this.healthCheckTimer) {
2051
+ clearInterval(this.healthCheckTimer);
2052
+ this.healthCheckTimer = void 0;
2053
+ }
2054
+ }
2055
+ startHealthChecks(interval) {
2056
+ this.healthCheckTimer = setInterval(() => {
2057
+ for (const provider of this.providers) {
2058
+ if (!provider.healthy) {
2059
+ this.checkHealth(provider);
2060
+ }
2061
+ }
2062
+ }, interval);
2063
+ if (this.healthCheckTimer.unref) {
2064
+ this.healthCheckTimer.unref();
2065
+ }
2066
+ }
2067
+ async checkHealth(provider) {
2068
+ try {
2069
+ const controller = new AbortController();
2070
+ const timeout = setTimeout(() => controller.abort(), this.requestTimeout);
2071
+ const response = await fetch(provider.url, {
2072
+ method: "POST",
2073
+ headers: { "Content-Type": "application/json" },
2074
+ body: JSON.stringify({
2075
+ jsonrpc: "2.0",
2076
+ method: "eth_chainId",
2077
+ params: [],
2078
+ id: 1
2079
+ }),
2080
+ signal: controller.signal
2081
+ });
2082
+ clearTimeout(timeout);
2083
+ if (response.ok) {
2084
+ provider.healthy = true;
2085
+ provider.consecutiveFailures = 0;
2086
+ provider.lastChecked = Date.now();
2087
+ return true;
2088
+ }
2089
+ } catch {
2090
+ }
2091
+ provider.lastChecked = Date.now();
2092
+ return false;
2093
+ }
2094
+ };
2095
+ function createFailoverProvider(config) {
2096
+ if (typeof config === "string") return null;
2097
+ if (Array.isArray(config)) return new FailoverProvider({ urls: config });
2098
+ return new FailoverProvider(config);
2099
+ }
2100
+ function resolveRpcUrl(config) {
2101
+ if (typeof config === "string") return config;
2102
+ if (Array.isArray(config)) return config[0];
2103
+ return config.urls[0];
2104
+ }
2105
+
2106
+ // src/t402wdk.ts
2107
+ var SUPPORTED_WDK_RANGE = ">=1.0.0-beta.5 <2.0.0";
2108
+ function parseSemver(version) {
2109
+ const match = version.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
2110
+ if (!match) return null;
2111
+ return {
2112
+ major: parseInt(match[1], 10),
2113
+ minor: parseInt(match[2], 10),
2114
+ patch: parseInt(match[3], 10),
2115
+ prerelease: match[4] ?? ""
2116
+ };
2117
+ }
2118
+ function comparePrereleases(a, b) {
2119
+ if (a === b) return 0;
2120
+ if (a === "" && b !== "") return 1;
2121
+ if (a !== "" && b === "") return -1;
2122
+ const aParts = a.split(".");
2123
+ const bParts = b.split(".");
2124
+ const len = Math.max(aParts.length, bParts.length);
2125
+ for (let i = 0; i < len; i++) {
2126
+ const ap = aParts[i] ?? "";
2127
+ const bp = bParts[i] ?? "";
2128
+ const aNum = /^\d+$/.test(ap);
2129
+ const bNum = /^\d+$/.test(bp);
2130
+ if (aNum && bNum) {
2131
+ const diff = parseInt(ap, 10) - parseInt(bp, 10);
2132
+ if (diff !== 0) return diff;
2133
+ } else if (aNum !== bNum) {
2134
+ return aNum ? -1 : 1;
2135
+ } else {
2136
+ if (ap < bp) return -1;
2137
+ if (ap > bp) return 1;
2138
+ }
2139
+ }
2140
+ return 0;
2141
+ }
2142
+ function compareSemver(a, b) {
2143
+ const pa = parseSemver(a);
2144
+ const pb = parseSemver(b);
2145
+ if (!pa || !pb) return 0;
2146
+ if (pa.major !== pb.major) return pa.major - pb.major > 0 ? 1 : -1;
2147
+ if (pa.minor !== pb.minor) return pa.minor - pb.minor > 0 ? 1 : -1;
2148
+ if (pa.patch !== pb.patch) return pa.patch - pb.patch > 0 ? 1 : -1;
2149
+ return comparePrereleases(pa.prerelease, pb.prerelease);
2150
+ }
2151
+ function satisfiesSemverRange(version, range) {
2152
+ const parsed = parseSemver(version);
2153
+ if (!parsed) return false;
2154
+ const constraints = range.trim().split(/\s+/);
2155
+ for (const constraint of constraints) {
2156
+ const match = constraint.match(/^(>=|<=|>|<|=)(.+)$/);
2157
+ if (!match) continue;
2158
+ const [, op, target] = match;
2159
+ const cmp = compareSemver(version, target);
2160
+ switch (op) {
2161
+ case ">=":
2162
+ if (cmp < 0) return false;
2163
+ break;
2164
+ case ">":
2165
+ if (cmp <= 0) return false;
2166
+ break;
2167
+ case "<=":
2168
+ if (cmp > 0) return false;
2169
+ break;
2170
+ case "<":
2171
+ if (cmp >= 0) return false;
2172
+ break;
2173
+ case "=":
2174
+ if (cmp !== 0) return false;
2175
+ break;
2176
+ }
2177
+ }
2178
+ return true;
2179
+ }
1390
2180
  var T402WDK = class _T402WDK {
1391
2181
  _wdk = null;
1392
2182
  _normalizedChains = /* @__PURE__ */ new Map();
@@ -1394,17 +2184,107 @@ var T402WDK = class _T402WDK {
1394
2184
  _signerCache = /* @__PURE__ */ new Map();
1395
2185
  _balanceCache;
1396
2186
  _initializationError = null;
1397
- // WDK module references (set via registerWDK)
1398
- static _WDK = null;
1399
- static _WalletManagerEvm = null;
1400
- static _BridgeUsdt0Evm = null;
1401
- // Multi-chain wallet module storage
1402
- static _WalletModules = {};
1403
- static _ProtocolModules = {};
2187
+ _events = new T402EventEmitter();
2188
+ _receiptStore = new InMemoryReceiptStore();
2189
+ _disposed = false;
2190
+ // Instance-level module references (#204 multi-instance)
2191
+ _wdkConstructor = null;
2192
+ _walletManagerEvm = null;
2193
+ _bridgeUsdt0Evm = null;
2194
+ _walletModules = {};
2195
+ _protocolModules = {};
2196
+ _fiatOnRampProvider = null;
2197
+ _middlewares = /* @__PURE__ */ new Map();
2198
+ // Retry config (#202 network resilience)
2199
+ _retryConfig;
2200
+ // Failover providers (#195)
2201
+ _failoverProviders = /* @__PURE__ */ new Map();
2202
+ // Static defaults for backward compatibility (#204)
2203
+ static _defaultModules = {};
2204
+ // Legacy static accessors for tests that access _WDK, _WalletManagerEvm, etc.
2205
+ static get _WDK() {
2206
+ return _T402WDK._defaultModules.wdk ?? null;
2207
+ }
2208
+ static set _WDK(val) {
2209
+ if (val === null) {
2210
+ delete _T402WDK._defaultModules.wdk;
2211
+ } else {
2212
+ _T402WDK._defaultModules.wdk = val;
2213
+ }
2214
+ }
2215
+ static get _WalletManagerEvm() {
2216
+ return _T402WDK._defaultModules.walletManagerEvm ?? null;
2217
+ }
2218
+ static set _WalletManagerEvm(val) {
2219
+ if (val === null) {
2220
+ delete _T402WDK._defaultModules.walletManagerEvm;
2221
+ if (_T402WDK._defaultModules.wallets) {
2222
+ delete _T402WDK._defaultModules.wallets.evm;
2223
+ }
2224
+ } else {
2225
+ _T402WDK._defaultModules.walletManagerEvm = val;
2226
+ if (!_T402WDK._defaultModules.wallets) {
2227
+ _T402WDK._defaultModules.wallets = {};
2228
+ }
2229
+ _T402WDK._defaultModules.wallets.evm = val;
2230
+ }
2231
+ }
2232
+ static get _BridgeUsdt0Evm() {
2233
+ return _T402WDK._defaultModules.bridgeUsdt0Evm ?? null;
2234
+ }
2235
+ static set _BridgeUsdt0Evm(val) {
2236
+ if (val === null) {
2237
+ delete _T402WDK._defaultModules.bridgeUsdt0Evm;
2238
+ if (_T402WDK._defaultModules.protocols) {
2239
+ delete _T402WDK._defaultModules.protocols.bridgeUsdt0Evm;
2240
+ }
2241
+ } else {
2242
+ _T402WDK._defaultModules.bridgeUsdt0Evm = val;
2243
+ if (!_T402WDK._defaultModules.protocols) {
2244
+ _T402WDK._defaultModules.protocols = {};
2245
+ }
2246
+ _T402WDK._defaultModules.protocols.bridgeUsdt0Evm = val;
2247
+ }
2248
+ }
2249
+ static get _WalletModules() {
2250
+ return _T402WDK._defaultModules.wallets ?? {};
2251
+ }
2252
+ static set _WalletModules(val) {
2253
+ _T402WDK._defaultModules.wallets = val;
2254
+ }
2255
+ static get _ProtocolModules() {
2256
+ return _T402WDK._defaultModules.protocols ?? {};
2257
+ }
2258
+ static set _ProtocolModules(val) {
2259
+ _T402WDK._defaultModules.protocols = val;
2260
+ }
2261
+ static get _fiatOnRampProvider() {
2262
+ return _T402WDK._defaultModules.fiatOnRampProvider ?? null;
2263
+ }
2264
+ static set _fiatOnRampProvider(val) {
2265
+ if (val === null) {
2266
+ delete _T402WDK._defaultModules.fiatOnRampProvider;
2267
+ } else {
2268
+ _T402WDK._defaultModules.fiatOnRampProvider = val;
2269
+ }
2270
+ }
2271
+ static get _middlewares() {
2272
+ if (!_T402WDK._defaultModules.middlewares) {
2273
+ _T402WDK._defaultModules.middlewares = /* @__PURE__ */ new Map();
2274
+ }
2275
+ return _T402WDK._defaultModules.middlewares;
2276
+ }
2277
+ static set _middlewares(val) {
2278
+ _T402WDK._defaultModules.middlewares = val;
2279
+ }
2280
+ // HD path-derived signer cache
2281
+ _pathSignerCache = /* @__PURE__ */ new Map();
1404
2282
  // Multi-chain signer caches
1405
2283
  _tonSignerCache = /* @__PURE__ */ new Map();
1406
2284
  _svmSignerCache = /* @__PURE__ */ new Map();
1407
2285
  _tronSignerCache = /* @__PURE__ */ new Map();
2286
+ _sparkSignerCache = /* @__PURE__ */ new Map();
2287
+ _btcSignerCache = /* @__PURE__ */ new Map();
1408
2288
  /**
1409
2289
  * Register the Tether WDK modules
1410
2290
  *
@@ -1443,6 +2323,14 @@ var T402WDK = class _T402WDK {
1443
2323
  if (typeof WDK !== "function") {
1444
2324
  throw new WDKInitializationError("WDK must be a constructor function");
1445
2325
  }
2326
+ const wdkVersion = WDK.version;
2327
+ if (wdkVersion && typeof wdkVersion === "string") {
2328
+ if (!satisfiesSemverRange(wdkVersion, SUPPORTED_WDK_RANGE)) {
2329
+ throw new WDKInitializationError(
2330
+ `WDK version ${wdkVersion} is not supported. Required: ${SUPPORTED_WDK_RANGE}`
2331
+ );
2332
+ }
2333
+ }
1446
2334
  _T402WDK._WDK = WDK;
1447
2335
  if (modulesOrWalletManager && typeof modulesOrWalletManager === "object" && ("wallets" in modulesOrWalletManager || "protocols" in modulesOrWalletManager)) {
1448
2336
  const modules = modulesOrWalletManager;
@@ -1493,6 +2381,18 @@ var T402WDK = class _T402WDK {
1493
2381
  static isTronRegistered() {
1494
2382
  return _T402WDK._WalletModules.tron !== void 0;
1495
2383
  }
2384
+ /**
2385
+ * Check if Spark wallet manager is registered
2386
+ */
2387
+ static isSparkRegistered() {
2388
+ return _T402WDK._WalletModules.spark !== void 0;
2389
+ }
2390
+ /**
2391
+ * Check if Bitcoin wallet manager is registered
2392
+ */
2393
+ static isBtcRegistered() {
2394
+ return _T402WDK._WalletModules.btc !== void 0;
2395
+ }
1496
2396
  /**
1497
2397
  * Get all registered wallet modules
1498
2398
  */
@@ -1510,15 +2410,71 @@ var T402WDK = class _T402WDK {
1510
2410
  );
1511
2411
  }
1512
2412
  /**
1513
- * Generate a new random seed phrase
2413
+ * Register a fiat on-ramp provider
1514
2414
  *
1515
- * @throws {WDKInitializationError} If WDK is not registered
1516
- * @returns A new BIP-39 mnemonic seed phrase
2415
+ * @param provider - A FiatOnRampProvider implementation (e.g., MoonpayOnRampProvider)
2416
+ *
2417
+ * @example
2418
+ * ```typescript
2419
+ * import { T402WDK, MoonpayOnRampProvider } from '@t402/wdk';
2420
+ *
2421
+ * T402WDK.registerFiatOnRamp(new MoonpayOnRampProvider({ apiKey: 'pk_test_...' }));
2422
+ * ```
1517
2423
  */
1518
- static generateSeedPhrase() {
1519
- if (!_T402WDK._WDK) {
1520
- throw new WDKInitializationError(
1521
- "WDK not registered. Call T402WDK.registerWDK() first, or use a mock seed phrase for testing."
2424
+ static registerFiatOnRamp(provider) {
2425
+ if (!provider || typeof provider.getQuote !== "function") {
2426
+ throw new WDKInitializationError("A valid FiatOnRampProvider is required");
2427
+ }
2428
+ _T402WDK._fiatOnRampProvider = provider;
2429
+ }
2430
+ /**
2431
+ * Check if a fiat on-ramp provider is registered
2432
+ */
2433
+ static isFiatOnRampRegistered() {
2434
+ return _T402WDK._fiatOnRampProvider !== null;
2435
+ }
2436
+ /**
2437
+ * Register a pricing provider for fiat-to-crypto rate conversion
2438
+ */
2439
+ static registerPricingProvider(provider) {
2440
+ registerPricingProvider(provider);
2441
+ }
2442
+ /**
2443
+ * Check if a pricing provider is registered
2444
+ */
2445
+ static isPricingProviderRegistered() {
2446
+ return isPricingProviderRegistered();
2447
+ }
2448
+ /**
2449
+ * Register a middleware for a chain
2450
+ */
2451
+ static registerMiddleware(chain, fn) {
2452
+ const existing = _T402WDK._middlewares.get(chain) ?? [];
2453
+ existing.push(fn);
2454
+ _T402WDK._middlewares.set(chain, existing);
2455
+ }
2456
+ /**
2457
+ * Get registered middlewares for a chain
2458
+ */
2459
+ static getMiddlewares(chain) {
2460
+ return _T402WDK._middlewares.get(chain) ?? [];
2461
+ }
2462
+ /**
2463
+ * Clear all middlewares
2464
+ */
2465
+ static clearMiddlewares() {
2466
+ _T402WDK._middlewares.clear();
2467
+ }
2468
+ /**
2469
+ * Generate a new random seed phrase
2470
+ *
2471
+ * @throws {WDKInitializationError} If WDK is not registered
2472
+ * @returns A new BIP-39 mnemonic seed phrase
2473
+ */
2474
+ static generateSeedPhrase() {
2475
+ if (!_T402WDK._WDK) {
2476
+ throw new WDKInitializationError(
2477
+ "WDK not registered. Call T402WDK.registerWDK() first, or use a mock seed phrase for testing."
1522
2478
  );
1523
2479
  }
1524
2480
  try {
@@ -1559,6 +2515,131 @@ var T402WDK = class _T402WDK {
1559
2515
  _T402WDK.registerWDK(WDK, config.modules);
1560
2516
  return new _T402WDK(config.seedPhrase, config.chains, config.options);
1561
2517
  }
2518
+ /**
2519
+ * Auto-discover installed WDK packages using dynamic imports.
2520
+ *
2521
+ * Probes known `@tetherto/wdk-*` packages and returns the ones that
2522
+ * are installed and importable.
2523
+ *
2524
+ * @returns Discovery result with available/unavailable packages and ready-to-use modules config
2525
+ *
2526
+ * @example
2527
+ * ```typescript
2528
+ * const result = await T402WDK.autoDiscover();
2529
+ * console.log('Found:', result.available);
2530
+ * console.log('Missing:', result.unavailable);
2531
+ * ```
2532
+ */
2533
+ static async autoDiscover() {
2534
+ const walletPackages = {
2535
+ evm: "@tetherto/wdk-wallet-evm",
2536
+ solana: "@tetherto/wdk-wallet-solana",
2537
+ ton: "@tetherto/wdk-wallet-ton",
2538
+ tron: "@tetherto/wdk-wallet-tron",
2539
+ btc: "@tetherto/wdk-wallet-btc",
2540
+ spark: "@buildonspark/spark-sdk",
2541
+ evmErc4337: "@tetherto/wdk-wallet-evm-erc-4337",
2542
+ tonGasless: "@tetherto/wdk-wallet-ton-gasless",
2543
+ tronGasfree: "@tetherto/wdk-wallet-tron-gasfree"
2544
+ };
2545
+ const protocolPackages = {
2546
+ bridgeUsdt0Evm: "@tetherto/wdk-protocol-bridge-usdt0-evm",
2547
+ bridgeUsdt0Ton: "@tetherto/wdk-protocol-bridge-usdt0-ton",
2548
+ swapVeloraEvm: "@tetherto/wdk-protocol-swap-velora-evm",
2549
+ lendingAaveEvm: "@tetherto/wdk-protocol-lending-aave-evm"
2550
+ };
2551
+ const available = [];
2552
+ const unavailable = [];
2553
+ const wallets = {};
2554
+ const protocols = {};
2555
+ const walletEntries = Object.entries(walletPackages);
2556
+ const walletResults = await Promise.allSettled(
2557
+ walletEntries.map(async ([key, pkg]) => {
2558
+ const mod = await import(
2559
+ /* @vite-ignore */
2560
+ pkg
2561
+ );
2562
+ return { key, pkg, mod: mod.default ?? mod };
2563
+ })
2564
+ );
2565
+ for (let i = 0; i < walletResults.length; i++) {
2566
+ const result = walletResults[i];
2567
+ if (result.status === "fulfilled") {
2568
+ const { key, pkg, mod } = result.value;
2569
+ wallets[key] = mod;
2570
+ available.push(pkg);
2571
+ } else {
2572
+ unavailable.push(walletEntries[i][1]);
2573
+ }
2574
+ }
2575
+ const protocolEntries = Object.entries(protocolPackages);
2576
+ const protocolResults = await Promise.allSettled(
2577
+ protocolEntries.map(async ([key, pkg]) => {
2578
+ const mod = await import(
2579
+ /* @vite-ignore */
2580
+ pkg
2581
+ );
2582
+ return { key, pkg, mod: mod.default ?? mod };
2583
+ })
2584
+ );
2585
+ for (let i = 0; i < protocolResults.length; i++) {
2586
+ const result = protocolResults[i];
2587
+ if (result.status === "fulfilled") {
2588
+ const { key, pkg, mod } = result.value;
2589
+ protocols[key] = mod;
2590
+ available.push(pkg);
2591
+ } else {
2592
+ unavailable.push(protocolEntries[i][1]);
2593
+ }
2594
+ }
2595
+ return {
2596
+ discovered: { wallets, protocols },
2597
+ available,
2598
+ unavailable
2599
+ };
2600
+ }
2601
+ /**
2602
+ * Auto-discover installed WDK modules, then create a fully configured T402WDK.
2603
+ *
2604
+ * Combines `autoDiscover()` + `create()` in one call. Any explicit
2605
+ * modules you pass in `config.modules` take precedence over discovered ones.
2606
+ *
2607
+ * @param config - Same as `T402WDKCreateConfig` but `modules` is optional/partial
2608
+ * @returns A ready-to-use T402WDK instance
2609
+ *
2610
+ * @example
2611
+ * ```typescript
2612
+ * const wdk = await T402WDK.autoCreate({
2613
+ * seedPhrase: 'your twelve word seed phrase ...',
2614
+ * chains: { arbitrum: 'https://arb1.arbitrum.io/rpc' },
2615
+ * });
2616
+ * ```
2617
+ */
2618
+ static async autoCreate(config) {
2619
+ const { discovered } = await _T402WDK.autoDiscover();
2620
+ const mergedModules = {
2621
+ wallets: { ...discovered.wallets, ...config.modules?.wallets },
2622
+ protocols: { ...discovered.protocols, ...config.modules?.protocols }
2623
+ };
2624
+ let WDKRef;
2625
+ try {
2626
+ const wdkMod = await import(
2627
+ /* @vite-ignore */
2628
+ "@tetherto/wdk"
2629
+ );
2630
+ WDKRef = wdkMod.default ?? wdkMod;
2631
+ } catch {
2632
+ throw new WDKInitializationError(
2633
+ "@tetherto/wdk package not found. Install it with: npm install @tetherto/wdk"
2634
+ );
2635
+ }
2636
+ return _T402WDK.create(WDKRef, {
2637
+ seedPhrase: config.seedPhrase,
2638
+ chains: config.chains,
2639
+ modules: mergedModules,
2640
+ options: config.options
2641
+ });
2642
+ }
1562
2643
  /**
1563
2644
  * Create a T402WDK from a pre-configured @tetherto/wdk instance.
1564
2645
  *
@@ -1578,6 +2659,31 @@ var T402WDK = class _T402WDK {
1578
2659
  instance._initializationError = null;
1579
2660
  return instance;
1580
2661
  }
2662
+ /**
2663
+ * Create a T402WDK instance from an encrypted seed.
2664
+ *
2665
+ * @example
2666
+ * ```typescript
2667
+ * const encrypted = JSON.parse(fs.readFileSync('seed.enc.json', 'utf8'))
2668
+ * const wdk = await T402WDK.fromEncryptedSeed(encrypted, 'my-password', {
2669
+ * arbitrum: 'https://arb1.arbitrum.io/rpc',
2670
+ * })
2671
+ * ```
2672
+ */
2673
+ static async fromEncryptedSeed(encrypted, password, config, options) {
2674
+ const seedPhrase = await decryptSeed(encrypted, password);
2675
+ return new _T402WDK(seedPhrase, config, options);
2676
+ }
2677
+ /**
2678
+ * Encrypt the current seed phrase for secure storage.
2679
+ *
2680
+ * @param password - Password to encrypt with
2681
+ * @returns Encrypted seed data suitable for JSON serialization
2682
+ */
2683
+ async encryptSeed(password) {
2684
+ this.assertNotDisposed();
2685
+ return encryptSeed(this._seedPhrase, password);
2686
+ }
1581
2687
  /**
1582
2688
  * Get all signers as an array ready for T402 HTTP clients.
1583
2689
  *
@@ -1591,6 +2697,7 @@ var T402WDK = class _T402WDK {
1591
2697
  * ```
1592
2698
  */
1593
2699
  async getAllSigners(options) {
2700
+ this.assertNotDisposed();
1594
2701
  const accountIndex = options?.accountIndex ?? 0;
1595
2702
  const schemes = options?.schemes ?? ["exact"];
1596
2703
  const includeNonEvm = options?.includeNonEvm ?? true;
@@ -1614,7 +2721,7 @@ var T402WDK = class _T402WDK {
1614
2721
  if (!includeNonEvm) {
1615
2722
  return entries;
1616
2723
  }
1617
- if (_T402WDK.isTonRegistered()) {
2724
+ if (this._walletModules.ton !== void 0) {
1618
2725
  try {
1619
2726
  const signer = await this.getTonSigner(accountIndex);
1620
2727
  for (const scheme of schemes) {
@@ -1623,7 +2730,7 @@ var T402WDK = class _T402WDK {
1623
2730
  } catch {
1624
2731
  }
1625
2732
  }
1626
- if (_T402WDK.isSolanaRegistered()) {
2733
+ if (this._walletModules.solana !== void 0) {
1627
2734
  try {
1628
2735
  const signer = await this.getSvmSigner(accountIndex);
1629
2736
  for (const scheme of schemes) {
@@ -1637,7 +2744,7 @@ var T402WDK = class _T402WDK {
1637
2744
  } catch {
1638
2745
  }
1639
2746
  }
1640
- if (_T402WDK.isTronRegistered()) {
2747
+ if (this._walletModules.tron !== void 0) {
1641
2748
  try {
1642
2749
  const signer = await this.getTronSigner(accountIndex);
1643
2750
  for (const scheme of schemes) {
@@ -1646,6 +2753,29 @@ var T402WDK = class _T402WDK {
1646
2753
  } catch {
1647
2754
  }
1648
2755
  }
2756
+ if (this._walletModules.spark !== void 0) {
2757
+ try {
2758
+ const signer = await this.getSparkSigner(accountIndex);
2759
+ for (const scheme of schemes) {
2760
+ entries.push({ scheme, network: "spark:mainnet", signer, family: "spark" });
2761
+ }
2762
+ } catch {
2763
+ }
2764
+ }
2765
+ if (this._walletModules.btc !== void 0) {
2766
+ try {
2767
+ const signer = await this.getBtcSigner(accountIndex);
2768
+ for (const scheme of schemes) {
2769
+ entries.push({
2770
+ scheme,
2771
+ network: "bip122:000000000019d6689c085ae165831e93",
2772
+ signer,
2773
+ family: "btc"
2774
+ });
2775
+ }
2776
+ } catch {
2777
+ }
2778
+ }
1649
2779
  return entries;
1650
2780
  }
1651
2781
  /**
@@ -1673,10 +2803,45 @@ var T402WDK = class _T402WDK {
1673
2803
  }
1674
2804
  this._seedPhrase = seedPhrase;
1675
2805
  this._balanceCache = new BalanceCache(options.cache);
2806
+ this._wdkConstructor = options.wdk ?? _T402WDK._defaultModules.wdk ?? null;
2807
+ this._walletModules = options.wallets ?? _T402WDK._defaultModules.wallets ?? {};
2808
+ this._protocolModules = options.protocols ?? _T402WDK._defaultModules.protocols ?? {};
2809
+ this._walletManagerEvm = this._walletModules.evm ?? _T402WDK._defaultModules.walletManagerEvm ?? null;
2810
+ this._bridgeUsdt0Evm = this._protocolModules.bridgeUsdt0Evm ?? _T402WDK._defaultModules.bridgeUsdt0Evm ?? null;
2811
+ this._fiatOnRampProvider = options.fiatOnRampProvider ?? _T402WDK._defaultModules.fiatOnRampProvider ?? null;
2812
+ if (options.middlewares) {
2813
+ this._middlewares = new Map(options.middlewares);
2814
+ } else if (_T402WDK._defaultModules.middlewares) {
2815
+ this._middlewares = new Map(_T402WDK._defaultModules.middlewares);
2816
+ }
2817
+ this._retryConfig = options.retry;
1676
2818
  for (const [chain, chainConfig] of Object.entries(config)) {
1677
2819
  if (chainConfig) {
1678
2820
  try {
1679
- this._normalizedChains.set(chain, normalizeChainConfig(chain, chainConfig));
2821
+ if (typeof chainConfig === "object" && "provider" in chainConfig && Array.isArray(chainConfig.provider)) {
2822
+ const urls = chainConfig.provider;
2823
+ if (urls.length === 0) {
2824
+ throw new Error("Provider array must contain at least one URL");
2825
+ }
2826
+ const failoverConfig = {
2827
+ urls,
2828
+ ...chainConfig.failover ?? {}
2829
+ };
2830
+ const failoverProvider = new FailoverProvider(failoverConfig);
2831
+ this._failoverProviders.set(chain, failoverProvider);
2832
+ const normalized = normalizeChainConfig(chain, failoverProvider.getCurrentUrl());
2833
+ if (chainConfig.chainId !== void 0) normalized.chainId = chainConfig.chainId;
2834
+ if (chainConfig.network !== void 0) normalized.network = chainConfig.network;
2835
+ this._normalizedChains.set(chain, normalized);
2836
+ } else {
2837
+ this._normalizedChains.set(
2838
+ chain,
2839
+ normalizeChainConfig(
2840
+ chain,
2841
+ chainConfig
2842
+ )
2843
+ );
2844
+ }
1680
2845
  } catch (error) {
1681
2846
  throw new ChainError(
1682
2847
  2003 /* INVALID_CHAIN_CONFIG */,
@@ -1687,10 +2852,24 @@ var T402WDK = class _T402WDK {
1687
2852
  }
1688
2853
  }
1689
2854
  this._addDefaultChainsIfNeeded();
1690
- if (!isFromWDK && _T402WDK._WDK) {
2855
+ if (!isFromWDK && this._wdkConstructor) {
1691
2856
  this._initializeWDK();
1692
2857
  }
1693
2858
  }
2859
+ /**
2860
+ * Guard: throw if this instance has been disposed (#194)
2861
+ */
2862
+ assertNotDisposed() {
2863
+ if (this._disposed) {
2864
+ throw new WDKError(1002 /* WDK_NOT_INITIALIZED */, "T402WDK has been disposed");
2865
+ }
2866
+ }
2867
+ /**
2868
+ * Whether this instance has been disposed
2869
+ */
2870
+ get isDisposed() {
2871
+ return this._disposed;
2872
+ }
1694
2873
  /**
1695
2874
  * Add default chain configurations for common chains
1696
2875
  */
@@ -1706,22 +2885,24 @@ var T402WDK = class _T402WDK {
1706
2885
  * Initialize the underlying WDK instance
1707
2886
  */
1708
2887
  _initializeWDK() {
1709
- if (!_T402WDK._WDK) {
2888
+ if (!this._wdkConstructor) {
1710
2889
  this._initializationError = new WDKInitializationError("WDK not registered");
1711
2890
  return;
1712
2891
  }
1713
- if (!_T402WDK._WalletManagerEvm) {
2892
+ if (!this._walletManagerEvm) {
1714
2893
  this._initializationError = new WDKInitializationError(
1715
2894
  "WalletManagerEvm not registered. Call T402WDK.registerWDK(WDK, WalletManagerEvm) to enable wallet functionality."
1716
2895
  );
1717
2896
  return;
1718
2897
  }
1719
2898
  try {
1720
- let wdk = new _T402WDK._WDK(this._seedPhrase);
2899
+ let wdk = new this._wdkConstructor(this._seedPhrase);
1721
2900
  for (const [chain, config] of this._normalizedChains) {
1722
2901
  try {
1723
- wdk = wdk.registerWallet(chain, _T402WDK._WalletManagerEvm, {
1724
- provider: config.provider,
2902
+ const failover = this._failoverProviders.get(chain);
2903
+ const providerUrl = failover ? failover.getCurrentUrl() : config.provider;
2904
+ wdk = wdk.registerWallet(chain, this._walletManagerEvm, {
2905
+ provider: providerUrl,
1725
2906
  chainId: config.chainId
1726
2907
  });
1727
2908
  } catch (error) {
@@ -1732,15 +2913,44 @@ var T402WDK = class _T402WDK {
1732
2913
  );
1733
2914
  }
1734
2915
  }
1735
- if (_T402WDK._BridgeUsdt0Evm) {
2916
+ if (this._bridgeUsdt0Evm) {
1736
2917
  try {
1737
- wdk = wdk.registerProtocol("bridge-usdt0", _T402WDK._BridgeUsdt0Evm);
2918
+ wdk = wdk.registerProtocol("bridge-usdt0", this._bridgeUsdt0Evm);
1738
2919
  } catch (error) {
1739
2920
  console.warn(
1740
2921
  `Failed to register USDT0 bridge protocol: ${error instanceof Error ? error.message : String(error)}`
1741
2922
  );
1742
2923
  }
1743
2924
  }
2925
+ if (this._protocolModules.swapVeloraEvm) {
2926
+ try {
2927
+ wdk = wdk.registerProtocol("swap-velora", this._protocolModules.swapVeloraEvm);
2928
+ } catch (error) {
2929
+ console.warn(
2930
+ `Failed to register Velora swap protocol: ${error instanceof Error ? error.message : String(error)}`
2931
+ );
2932
+ }
2933
+ }
2934
+ if (this._protocolModules.lendingAaveEvm) {
2935
+ try {
2936
+ wdk = wdk.registerProtocol("lending-aave", this._protocolModules.lendingAaveEvm);
2937
+ } catch (error) {
2938
+ console.warn(
2939
+ `Failed to register Aave lending protocol: ${error instanceof Error ? error.message : String(error)}`
2940
+ );
2941
+ }
2942
+ }
2943
+ if (typeof wdk.registerMiddleware === "function") {
2944
+ for (const [chain, fns] of this._middlewares) {
2945
+ for (const fn of fns) {
2946
+ try {
2947
+ ;
2948
+ wdk.registerMiddleware(chain, fn);
2949
+ } catch {
2950
+ }
2951
+ }
2952
+ }
2953
+ }
1744
2954
  this._wdk = wdk;
1745
2955
  this._initializationError = null;
1746
2956
  } catch (error) {
@@ -1779,6 +2989,47 @@ var T402WDK = class _T402WDK {
1779
2989
  get initializationError() {
1780
2990
  return this._initializationError;
1781
2991
  }
2992
+ // ========== Event Emitter ==========
2993
+ /**
2994
+ * Subscribe to a T402 event
2995
+ */
2996
+ on(event, handler) {
2997
+ this._events.on(event, handler);
2998
+ return this;
2999
+ }
3000
+ /**
3001
+ * Unsubscribe from a T402 event
3002
+ */
3003
+ off(event, handler) {
3004
+ this._events.off(event, handler);
3005
+ return this;
3006
+ }
3007
+ /**
3008
+ * Subscribe to a T402 event (fires once then auto-unsubscribes)
3009
+ */
3010
+ once(event, handler) {
3011
+ this._events.once(event, handler);
3012
+ return this;
3013
+ }
3014
+ /**
3015
+ * Emit a T402 event
3016
+ */
3017
+ emit(event, data) {
3018
+ return this._events.emit(event, data);
3019
+ }
3020
+ // ========== Receipt Store ==========
3021
+ /**
3022
+ * Get the payment receipt store
3023
+ */
3024
+ getReceiptStore() {
3025
+ return this._receiptStore;
3026
+ }
3027
+ /**
3028
+ * Set a custom payment receipt store backend
3029
+ */
3030
+ setReceiptStore(store) {
3031
+ this._receiptStore = store;
3032
+ }
1782
3033
  /**
1783
3034
  * Get all configured chains
1784
3035
  */
@@ -1807,6 +3058,7 @@ var T402WDK = class _T402WDK {
1807
3058
  * @returns An initialized WDKSigner
1808
3059
  */
1809
3060
  async getSigner(chain, accountIndex = 0) {
3061
+ this.assertNotDisposed();
1810
3062
  if (!chain || typeof chain !== "string") {
1811
3063
  throw new ChainError(
1812
3064
  2001 /* CHAIN_NOT_CONFIGURED */,
@@ -1830,6 +3082,11 @@ var T402WDK = class _T402WDK {
1830
3082
  try {
1831
3083
  const signer = await createWDKSigner(this.wdk, chain, accountIndex);
1832
3084
  this._signerCache.set(cacheKey, signer);
3085
+ this._events.emit("signer:initialized", {
3086
+ chain,
3087
+ address: signer.address,
3088
+ family: "evm"
3089
+ });
1833
3090
  return signer;
1834
3091
  } catch (error) {
1835
3092
  if (isWDKError(error)) {
@@ -1849,9 +3106,69 @@ var T402WDK = class _T402WDK {
1849
3106
  */
1850
3107
  clearSignerCache() {
1851
3108
  this._signerCache.clear();
3109
+ this._pathSignerCache.clear();
1852
3110
  this._tonSignerCache.clear();
1853
3111
  this._svmSignerCache.clear();
1854
3112
  this._tronSignerCache.clear();
3113
+ this._sparkSignerCache.clear();
3114
+ this._btcSignerCache.clear();
3115
+ }
3116
+ // ========== Fee Rates & Cost Estimation ==========
3117
+ /**
3118
+ * Get current fee rates for a chain
3119
+ */
3120
+ async getFeeRates(chain) {
3121
+ if (this._wdk && typeof this._wdk.getFeeRates === "function") {
3122
+ return this._wdk.getFeeRates(chain);
3123
+ }
3124
+ return { low: 1000000000n, medium: 2000000000n, high: 5000000000n };
3125
+ }
3126
+ /**
3127
+ * Estimate total cost of a payment on a chain
3128
+ */
3129
+ async estimatePaymentCost(chain, amount) {
3130
+ const signer = await this.getSigner(chain);
3131
+ const nativeBalance = await signer.getBalance();
3132
+ let estimatedGasCost = 100000n * 2000000000n;
3133
+ try {
3134
+ const feeRates = await this.getFeeRates(chain);
3135
+ const mediumRate = feeRates.medium ?? 2000000000n;
3136
+ estimatedGasCost = 100000n * mediumRate;
3137
+ } catch {
3138
+ }
3139
+ const config = this.getChainConfig(chain);
3140
+ return {
3141
+ paymentAmount: amount,
3142
+ estimatedGasCost,
3143
+ nativeBalance,
3144
+ canAffordGas: nativeBalance >= estimatedGasCost,
3145
+ chain,
3146
+ network: config?.network ?? ""
3147
+ };
3148
+ }
3149
+ // ========== HD Derivation Paths ==========
3150
+ /**
3151
+ * Get a signer using a custom BIP-44 derivation path
3152
+ */
3153
+ async getSignerByPath(chain, path) {
3154
+ const cacheKey = `${chain}:path:${path}`;
3155
+ const cached = this._pathSignerCache.get(cacheKey);
3156
+ if (cached) return cached;
3157
+ if (!this._wdk) {
3158
+ throw new WDKInitializationError("WDK not initialized");
3159
+ }
3160
+ if (typeof this._wdk.getAccountByPath !== "function") {
3161
+ throw new Error(
3162
+ "getAccountByPath not available. Upgrade @tetherto/wdk to support custom derivation paths."
3163
+ );
3164
+ }
3165
+ const account = await this._wdk.getAccountByPath(chain, path);
3166
+ const address = await account.getAddress();
3167
+ const signer = new WDKSigner(this._wdk, chain, 0);
3168
+ signer._account = account;
3169
+ signer._address = address;
3170
+ this._pathSignerCache.set(cacheKey, signer);
3171
+ return signer;
1855
3172
  }
1856
3173
  // ========== Multi-Chain Signers ==========
1857
3174
  /**
@@ -1871,11 +3188,12 @@ var T402WDK = class _T402WDK {
1871
3188
  * ```
1872
3189
  */
1873
3190
  async getTonSigner(accountIndex = 0) {
3191
+ this.assertNotDisposed();
1874
3192
  const cached = this._tonSignerCache.get(accountIndex);
1875
3193
  if (cached) {
1876
3194
  return cached;
1877
3195
  }
1878
- if (!_T402WDK._WalletModules.ton) {
3196
+ if (!this._walletModules.ton) {
1879
3197
  throw new ChainError(
1880
3198
  2002 /* CHAIN_NOT_SUPPORTED */,
1881
3199
  "TON wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { ton: WalletManagerTon } }).",
@@ -1886,6 +3204,11 @@ var T402WDK = class _T402WDK {
1886
3204
  const account = await this.wdk.getAccount("ton", accountIndex);
1887
3205
  const signer = await createWDKTonSigner(account);
1888
3206
  this._tonSignerCache.set(accountIndex, signer);
3207
+ this._events.emit("signer:initialized", {
3208
+ chain: "ton",
3209
+ address: signer.address.toString(),
3210
+ family: "ton"
3211
+ });
1889
3212
  return signer;
1890
3213
  } catch (error) {
1891
3214
  if (isWDKError(error)) {
@@ -1914,11 +3237,12 @@ var T402WDK = class _T402WDK {
1914
3237
  * ```
1915
3238
  */
1916
3239
  async getSvmSigner(accountIndex = 0) {
3240
+ this.assertNotDisposed();
1917
3241
  const cached = this._svmSignerCache.get(accountIndex);
1918
3242
  if (cached) {
1919
3243
  return cached;
1920
3244
  }
1921
- if (!_T402WDK._WalletModules.solana) {
3245
+ if (!this._walletModules.solana) {
1922
3246
  throw new ChainError(
1923
3247
  2002 /* CHAIN_NOT_SUPPORTED */,
1924
3248
  "Solana wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { solana: WalletManagerSolana } }).",
@@ -1932,6 +3256,11 @@ var T402WDK = class _T402WDK {
1932
3256
  );
1933
3257
  const signer = await createWDKSvmSigner(account);
1934
3258
  this._svmSignerCache.set(accountIndex, signer);
3259
+ this._events.emit("signer:initialized", {
3260
+ chain: "solana",
3261
+ address: signer.address.toString(),
3262
+ family: "svm"
3263
+ });
1935
3264
  return signer;
1936
3265
  } catch (error) {
1937
3266
  if (isWDKError(error)) {
@@ -1963,13 +3292,14 @@ var T402WDK = class _T402WDK {
1963
3292
  * ```
1964
3293
  */
1965
3294
  async getTronSigner(accountIndex = 0, rpcUrl) {
3295
+ this.assertNotDisposed();
1966
3296
  if (!rpcUrl) {
1967
3297
  const cached = this._tronSignerCache.get(accountIndex);
1968
3298
  if (cached) {
1969
3299
  return cached;
1970
3300
  }
1971
3301
  }
1972
- if (!_T402WDK._WalletModules.tron) {
3302
+ if (!this._walletModules.tron) {
1973
3303
  throw new ChainError(
1974
3304
  2002 /* CHAIN_NOT_SUPPORTED */,
1975
3305
  "TRON wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { tron: WalletManagerTron } }).",
@@ -1982,6 +3312,11 @@ var T402WDK = class _T402WDK {
1982
3312
  if (!rpcUrl) {
1983
3313
  this._tronSignerCache.set(accountIndex, signer);
1984
3314
  }
3315
+ this._events.emit("signer:initialized", {
3316
+ chain: "tron",
3317
+ address: signer.address,
3318
+ family: "tron"
3319
+ });
1985
3320
  return signer;
1986
3321
  } catch (error) {
1987
3322
  if (isWDKError(error)) {
@@ -1993,6 +3328,109 @@ var T402WDK = class _T402WDK {
1993
3328
  });
1994
3329
  }
1995
3330
  }
3331
+ /**
3332
+ * Get a Spark (Bitcoin L2) signer for T402 payments
3333
+ *
3334
+ * @param accountIndex - HD wallet account index (default: 0)
3335
+ * @throws {ChainError} If Spark wallet manager is not registered
3336
+ * @returns An initialized WDKSparkSignerAdapter
3337
+ *
3338
+ * @example
3339
+ * ```typescript
3340
+ * const sparkSigner = await wallet.getSparkSigner();
3341
+ *
3342
+ * const client = createT402HTTPClient({
3343
+ * signers: [{ scheme: 'exact', network: 'spark:mainnet', signer: sparkSigner }]
3344
+ * });
3345
+ * ```
3346
+ */
3347
+ async getSparkSigner(accountIndex = 0) {
3348
+ this.assertNotDisposed();
3349
+ const cached = this._sparkSignerCache.get(accountIndex);
3350
+ if (cached) {
3351
+ return cached;
3352
+ }
3353
+ if (!this._walletModules.spark) {
3354
+ throw new ChainError(
3355
+ 2002 /* CHAIN_NOT_SUPPORTED */,
3356
+ "Spark wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { spark: SparkWalletManager } }).",
3357
+ { chain: "spark" }
3358
+ );
3359
+ }
3360
+ try {
3361
+ const account = await this.wdk.getAccount(
3362
+ "spark",
3363
+ accountIndex
3364
+ );
3365
+ const signer = await createWDKSparkSigner(account);
3366
+ this._sparkSignerCache.set(accountIndex, signer);
3367
+ this._events.emit("signer:initialized", {
3368
+ chain: "spark",
3369
+ address: signer.address,
3370
+ family: "spark"
3371
+ });
3372
+ return signer;
3373
+ } catch (error) {
3374
+ if (isWDKError(error)) {
3375
+ throw error;
3376
+ }
3377
+ throw wrapError(error, 3001 /* SIGNER_NOT_INITIALIZED */, "Failed to create Spark signer", {
3378
+ chain: "spark",
3379
+ accountIndex
3380
+ });
3381
+ }
3382
+ }
3383
+ /**
3384
+ * Get a Bitcoin (BTC) on-chain signer for T402 payments
3385
+ *
3386
+ * @param accountIndex - HD wallet account index (default: 0)
3387
+ * @throws {ChainError} If Bitcoin wallet manager is not registered
3388
+ * @returns An initialized WDKBtcSignerAdapter
3389
+ *
3390
+ * @example
3391
+ * ```typescript
3392
+ * const btcSigner = await wallet.getBtcSigner();
3393
+ *
3394
+ * const client = createT402HTTPClient({
3395
+ * signers: [{ scheme: 'exact', network: 'bip122:000000000019d6689c085ae165831e93', signer: btcSigner }]
3396
+ * });
3397
+ * ```
3398
+ */
3399
+ async getBtcSigner(accountIndex = 0) {
3400
+ this.assertNotDisposed();
3401
+ const cached = this._btcSignerCache.get(accountIndex);
3402
+ if (cached) {
3403
+ return cached;
3404
+ }
3405
+ if (!this._walletModules.btc) {
3406
+ throw new ChainError(
3407
+ 2002 /* CHAIN_NOT_SUPPORTED */,
3408
+ "Bitcoin wallet manager not registered. Call T402WDK.registerWDK(WDK, { wallets: { btc: WalletManagerBtc } }).",
3409
+ { chain: "btc" }
3410
+ );
3411
+ }
3412
+ try {
3413
+ const account = await this.wdk.getAccount("btc", accountIndex);
3414
+ const signer = await createWDKBtcSigner(account);
3415
+ this._btcSignerCache.set(accountIndex, signer);
3416
+ this._events.emit("signer:initialized", {
3417
+ chain: "btc",
3418
+ address: signer.address,
3419
+ family: "btc"
3420
+ });
3421
+ return signer;
3422
+ } catch (error) {
3423
+ if (isWDKError(error)) {
3424
+ throw error;
3425
+ }
3426
+ throw wrapError(
3427
+ error,
3428
+ 3001 /* SIGNER_NOT_INITIALIZED */,
3429
+ "Failed to create Bitcoin signer",
3430
+ { chain: "btc", accountIndex }
3431
+ );
3432
+ }
3433
+ }
1996
3434
  /**
1997
3435
  * Get a signer for a specific chain family
1998
3436
  *
@@ -2031,10 +3469,14 @@ var T402WDK = class _T402WDK {
2031
3469
  return this.getSvmSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
2032
3470
  case "tron":
2033
3471
  return this.getTronSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
3472
+ case "spark":
3473
+ return this.getSparkSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
3474
+ case "btc":
3475
+ return this.getBtcSigner(typeof chainOrIndex === "number" ? chainOrIndex : accountIndex);
2034
3476
  default:
2035
3477
  throw new ChainError(
2036
3478
  2002 /* CHAIN_NOT_SUPPORTED */,
2037
- `Chain family "${family}" is not supported. Available: evm, ton, svm, tron`,
3479
+ `Chain family "${family}" is not supported. Available: evm, ton, svm, tron, spark, btc`,
2038
3480
  { chain: family }
2039
3481
  );
2040
3482
  }
@@ -2048,6 +3490,7 @@ var T402WDK = class _T402WDK {
2048
3490
  * @throws {SignerError} If address fetch fails
2049
3491
  */
2050
3492
  async getAddress(chain, accountIndex = 0) {
3493
+ this.assertNotDisposed();
2051
3494
  const signer = await this.getSigner(chain, accountIndex);
2052
3495
  return signer.address;
2053
3496
  }
@@ -2059,6 +3502,7 @@ var T402WDK = class _T402WDK {
2059
3502
  * @throws {BalanceError} If balance fetch fails
2060
3503
  */
2061
3504
  async getUsdt0Balance(chain, accountIndex = 0) {
3505
+ this.assertNotDisposed();
2062
3506
  const usdt0Address = USDT0_ADDRESSES[chain];
2063
3507
  if (!usdt0Address) {
2064
3508
  return 0n;
@@ -2070,7 +3514,7 @@ var T402WDK = class _T402WDK {
2070
3514
  chain,
2071
3515
  usdt0Address,
2072
3516
  address,
2073
- async () => signer.getTokenBalance(usdt0Address)
3517
+ () => this._withRetry(() => signer.getTokenBalance(usdt0Address))
2074
3518
  );
2075
3519
  } catch (error) {
2076
3520
  if (isWDKError(error) && error.code === 5002 /* TOKEN_BALANCE_FETCH_FAILED */) {
@@ -2087,6 +3531,7 @@ var T402WDK = class _T402WDK {
2087
3531
  * @throws {BalanceError} If balance fetch fails
2088
3532
  */
2089
3533
  async getUsdcBalance(chain, accountIndex = 0) {
3534
+ this.assertNotDisposed();
2090
3535
  const usdcAddress = USDC_ADDRESSES[chain];
2091
3536
  if (!usdcAddress) {
2092
3537
  return 0n;
@@ -2098,7 +3543,7 @@ var T402WDK = class _T402WDK {
2098
3543
  chain,
2099
3544
  usdcAddress,
2100
3545
  address,
2101
- async () => signer.getTokenBalance(usdcAddress)
3546
+ () => this._withRetry(() => signer.getTokenBalance(usdcAddress))
2102
3547
  );
2103
3548
  } catch (error) {
2104
3549
  if (isWDKError(error) && error.code === 5002 /* TOKEN_BALANCE_FETCH_FAILED */) {
@@ -2116,6 +3561,7 @@ var T402WDK = class _T402WDK {
2116
3561
  * @throws {BalanceError} If balance fetch fails
2117
3562
  */
2118
3563
  async getChainBalances(chain, accountIndex = 0) {
3564
+ this.assertNotDisposed();
2119
3565
  const config = this._normalizedChains.get(chain);
2120
3566
  if (!config) {
2121
3567
  throw new ChainError(2001 /* CHAIN_NOT_CONFIGURED */, `Chain "${chain}" not configured`, {
@@ -2132,7 +3578,7 @@ var T402WDK = class _T402WDK {
2132
3578
  chain,
2133
3579
  token.address,
2134
3580
  address,
2135
- async () => signer.getTokenBalance(token.address)
3581
+ () => this._withRetry(() => signer.getTokenBalance(token.address))
2136
3582
  );
2137
3583
  return {
2138
3584
  token: token.address,
@@ -2161,7 +3607,7 @@ var T402WDK = class _T402WDK {
2161
3607
  nativeBalance = await this._balanceCache.getOrFetchNativeBalance(
2162
3608
  chain,
2163
3609
  address,
2164
- async () => signer.getBalance()
3610
+ () => this._withRetry(() => signer.getBalance())
2165
3611
  );
2166
3612
  } catch {
2167
3613
  nativeBalance = 0n;
@@ -2254,6 +3700,16 @@ var T402WDK = class _T402WDK {
2254
3700
  for (const chainBalance of balances.chains) {
2255
3701
  const tokenBalance = chainBalance.tokens.find((t) => t.symbol === tokenSymbol);
2256
3702
  if (tokenBalance && tokenBalance.balance >= amount) {
3703
+ try {
3704
+ const costEstimate = await this.estimatePaymentCost(
3705
+ chainBalance.chain,
3706
+ amount.toString()
3707
+ );
3708
+ if (!costEstimate.canAffordGas) {
3709
+ continue;
3710
+ }
3711
+ } catch {
3712
+ }
2257
3713
  return {
2258
3714
  chain: chainBalance.chain,
2259
3715
  token: tokenSymbol,
@@ -2287,7 +3743,8 @@ var T402WDK = class _T402WDK {
2287
3743
  * @returns Bridge result with transaction hash
2288
3744
  */
2289
3745
  async bridgeUsdt0(params) {
2290
- if (!_T402WDK._BridgeUsdt0Evm) {
3746
+ this.assertNotDisposed();
3747
+ if (!this._bridgeUsdt0Evm) {
2291
3748
  throw new BridgeError(
2292
3749
  7001 /* BRIDGE_NOT_AVAILABLE */,
2293
3750
  "USDT0 bridge not available. Register BridgeUsdt0Evm with T402WDK.registerWDK().",
@@ -2322,6 +3779,11 @@ var T402WDK = class _T402WDK {
2322
3779
  }
2323
3780
  try {
2324
3781
  const recipient = params.recipient ?? await this.getAddress(params.toChain);
3782
+ this._events.emit("bridge:start", {
3783
+ fromChain: params.fromChain,
3784
+ toChain: params.toChain,
3785
+ amount: params.amount
3786
+ });
2325
3787
  const result = await this.wdk.executeProtocol("bridge-usdt0", {
2326
3788
  fromChain: params.fromChain,
2327
3789
  toChain: params.toChain,
@@ -2335,6 +3797,11 @@ var T402WDK = class _T402WDK {
2335
3797
  { fromChain: params.fromChain, toChain: params.toChain }
2336
3798
  );
2337
3799
  }
3800
+ this._events.emit("bridge:confirmed", {
3801
+ txHash: result.txHash,
3802
+ fromChain: params.fromChain,
3803
+ toChain: params.toChain
3804
+ });
2338
3805
  return {
2339
3806
  txHash: result.txHash,
2340
3807
  estimatedTime: 300
@@ -2390,7 +3857,7 @@ var T402WDK = class _T402WDK {
2390
3857
  * Check if the Velora swap protocol is registered and available
2391
3858
  */
2392
3859
  canSwap() {
2393
- return _T402WDK._ProtocolModules.swapVeloraEvm !== void 0;
3860
+ return this._protocolModules.swapVeloraEvm !== void 0;
2394
3861
  }
2395
3862
  /**
2396
3863
  * Get a swap quote for converting a token to USDT0
@@ -2497,18 +3964,143 @@ var T402WDK = class _T402WDK {
2497
3964
  );
2498
3965
  }
2499
3966
  }
2500
- // ========== Cache Management ==========
3967
+ // ========== Lending Protocol ==========
2501
3968
  /**
2502
- * Check if balance caching is enabled
3969
+ * Check if the Aave lending protocol is registered and available
2503
3970
  */
2504
- get isCacheEnabled() {
2505
- return this._balanceCache.enabled;
3971
+ canBorrow() {
3972
+ return this._protocolModules.lendingAaveEvm !== void 0;
2506
3973
  }
2507
3974
  /**
2508
- * Get cache configuration
3975
+ * Borrow USDT0 against collateral and pay
3976
+ *
3977
+ * Uses the Aave protocol to deposit collateral, borrow USDT0, then the
3978
+ * borrowed USDT0 is available for T402 payments.
3979
+ *
3980
+ * @param params - Borrow parameters
3981
+ * @throws {WDKError} If lending protocol is not registered or borrow fails
3982
+ *
3983
+ * @example
3984
+ * ```typescript
3985
+ * // Borrow 100 USDT0 against 0.05 WETH on Arbitrum
3986
+ * const result = await wallet.borrowAndPay({
3987
+ * chain: 'arbitrum',
3988
+ * collateralToken: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', // WETH
3989
+ * collateralAmount: 50000000000000000n, // 0.05 WETH
3990
+ * borrowAmount: 100000000n, // 100 USDT0
3991
+ * });
3992
+ * ```
2509
3993
  */
2510
- getCacheConfig() {
2511
- return this._balanceCache.config;
3994
+ async borrowAndPay(params) {
3995
+ if (!this.canBorrow()) {
3996
+ throw new WDKError(
3997
+ 8101 /* PROTOCOL_NOT_REGISTERED */,
3998
+ "Aave lending protocol not registered. Call T402WDK.registerWDK(WDK, { protocols: { lendingAaveEvm: LendingAaveEvm } })."
3999
+ );
4000
+ }
4001
+ const usdt0Address = USDT0_ADDRESSES[params.chain];
4002
+ if (!usdt0Address) {
4003
+ throw new ChainError(
4004
+ 2002 /* CHAIN_NOT_SUPPORTED */,
4005
+ `Chain "${params.chain}" does not have a known USDT0 address`,
4006
+ { chain: params.chain }
4007
+ );
4008
+ }
4009
+ if (params.collateralAmount <= 0n) {
4010
+ throw new WDKError(8103 /* INVALID_PARAMETER */, "collateralAmount must be greater than 0");
4011
+ }
4012
+ if (params.borrowAmount <= 0n) {
4013
+ throw new WDKError(8103 /* INVALID_PARAMETER */, "borrowAmount must be greater than 0");
4014
+ }
4015
+ try {
4016
+ const result = await this.wdk.executeProtocol("lending-aave", {
4017
+ action: "borrow",
4018
+ chain: params.chain,
4019
+ collateralToken: params.collateralToken,
4020
+ collateralAmount: params.collateralAmount.toString(),
4021
+ borrowToken: usdt0Address,
4022
+ borrowAmount: params.borrowAmount.toString(),
4023
+ interestRateMode: params.interestRateMode ?? 2
4024
+ });
4025
+ this._balanceCache.invalidateChain(params.chain);
4026
+ const r = result;
4027
+ return {
4028
+ supplyTxHash: r.supplyTxHash,
4029
+ borrowTxHash: r.borrowTxHash,
4030
+ borrowedAmount: BigInt(r.borrowedAmount)
4031
+ };
4032
+ } catch (error) {
4033
+ throw wrapError(
4034
+ error,
4035
+ 8102 /* PROTOCOL_EXECUTION_FAILED */,
4036
+ `Failed to execute borrow on ${params.chain}`,
4037
+ {
4038
+ chain: params.chain,
4039
+ collateralToken: params.collateralToken,
4040
+ borrowAmount: params.borrowAmount.toString()
4041
+ }
4042
+ );
4043
+ }
4044
+ }
4045
+ // ========== Fiat On-Ramp ==========
4046
+ /**
4047
+ * Get a fiat on-ramp quote
4048
+ *
4049
+ * @param params - Quote parameters (fiatAmount, fiatCurrency, network)
4050
+ * @throws {WDKError} If no fiat on-ramp provider is registered
4051
+ */
4052
+ async getFiatOnRampQuote(params) {
4053
+ this.assertNotDisposed();
4054
+ if (!this._fiatOnRampProvider) {
4055
+ throw new WDKError(
4056
+ 8101 /* PROTOCOL_NOT_REGISTERED */,
4057
+ "No fiat on-ramp provider registered. Call T402WDK.registerFiatOnRamp() first."
4058
+ );
4059
+ }
4060
+ return this._fiatOnRampProvider.getQuote(params);
4061
+ }
4062
+ /**
4063
+ * Generate a fiat on-ramp widget URL for the user
4064
+ *
4065
+ * Returns a widget URL that the application should open in a browser
4066
+ * or webview so the user can complete the fiat purchase.
4067
+ *
4068
+ * @param params - On-ramp parameters
4069
+ * @throws {WDKError} If no fiat on-ramp provider is registered
4070
+ *
4071
+ * @example
4072
+ * ```typescript
4073
+ * const result = await wallet.onRampAndPay({
4074
+ * fiatAmount: 100,
4075
+ * fiatCurrency: 'USD',
4076
+ * walletAddress: '0x...',
4077
+ * network: 'eip155:42161',
4078
+ * });
4079
+ * // Open result.widgetUrl in browser/webview
4080
+ * ```
4081
+ */
4082
+ onRampAndPay(params) {
4083
+ this.assertNotDisposed();
4084
+ if (!this._fiatOnRampProvider) {
4085
+ throw new WDKError(
4086
+ 8101 /* PROTOCOL_NOT_REGISTERED */,
4087
+ "No fiat on-ramp provider registered. Call T402WDK.registerFiatOnRamp() first."
4088
+ );
4089
+ }
4090
+ return this._fiatOnRampProvider.createWidget(params);
4091
+ }
4092
+ // ========== Cache Management ==========
4093
+ /**
4094
+ * Check if balance caching is enabled
4095
+ */
4096
+ get isCacheEnabled() {
4097
+ return this._balanceCache.enabled;
4098
+ }
4099
+ /**
4100
+ * Get cache configuration
4101
+ */
4102
+ getCacheConfig() {
4103
+ return this._balanceCache.config;
2512
4104
  }
2513
4105
  /**
2514
4106
  * Get cache statistics
@@ -2523,6 +4115,14 @@ var T402WDK = class _T402WDK {
2523
4115
  */
2524
4116
  invalidateBalanceCache() {
2525
4117
  this._balanceCache.clear();
4118
+ for (const chain of this.getConfiguredChains()) {
4119
+ this._events.emit("balance:changed", {
4120
+ chain,
4121
+ token: "*",
4122
+ previousBalance: 0n,
4123
+ newBalance: 0n
4124
+ });
4125
+ }
2526
4126
  }
2527
4127
  /**
2528
4128
  * Invalidate cached balances for a specific chain
@@ -2531,7 +4131,16 @@ var T402WDK = class _T402WDK {
2531
4131
  * @returns Number of cache entries invalidated
2532
4132
  */
2533
4133
  invalidateChainCache(chain) {
2534
- return this._balanceCache.invalidateChain(chain);
4134
+ const count = this._balanceCache.invalidateChain(chain);
4135
+ if (count > 0) {
4136
+ this._events.emit("balance:changed", {
4137
+ chain,
4138
+ token: "*",
4139
+ previousBalance: 0n,
4140
+ newBalance: 0n
4141
+ });
4142
+ }
4143
+ return count;
2535
4144
  }
2536
4145
  /**
2537
4146
  * Invalidate cached balances for a specific address
@@ -2543,16 +4152,92 @@ var T402WDK = class _T402WDK {
2543
4152
  return this._balanceCache.invalidateAddress(address);
2544
4153
  }
2545
4154
  /**
2546
- * Dispose of cache resources
4155
+ * Dispose of all resources held by this instance (#194).
2547
4156
  *
2548
- * Call this when the T402WDK instance is no longer needed.
4157
+ * After disposal, any public method call will throw.
4158
+ * Safe to call multiple times.
2549
4159
  */
2550
4160
  dispose() {
2551
- this._balanceCache.dispose();
4161
+ if (this._disposed) return;
4162
+ this._disposed = true;
4163
+ if (this._wdk && typeof this._wdk.dispose === "function") {
4164
+ try {
4165
+ ;
4166
+ this._wdk.dispose();
4167
+ } catch {
4168
+ }
4169
+ }
4170
+ this._wdk = null;
2552
4171
  this._signerCache.clear();
4172
+ this._pathSignerCache.clear();
2553
4173
  this._tonSignerCache.clear();
2554
4174
  this._svmSignerCache.clear();
2555
4175
  this._tronSignerCache.clear();
4176
+ this._sparkSignerCache.clear();
4177
+ this._btcSignerCache.clear();
4178
+ this._seedPhrase = "";
4179
+ this._balanceCache.dispose();
4180
+ for (const provider of this._failoverProviders.values()) {
4181
+ provider.dispose();
4182
+ }
4183
+ this._failoverProviders.clear();
4184
+ }
4185
+ /**
4186
+ * Symbol.dispose support for `using` declarations (TC39 Explicit Resource Management)
4187
+ */
4188
+ [Symbol.dispose]() {
4189
+ this.dispose();
4190
+ }
4191
+ // ========== Failover Provider Status (#195) ==========
4192
+ /**
4193
+ * Get the FailoverProvider status for a chain, if one exists.
4194
+ *
4195
+ * @param chain - Chain name
4196
+ * @returns Array of provider statuses, or null if no failover is configured for the chain
4197
+ */
4198
+ getProviderStatus(chain) {
4199
+ const provider = this._failoverProviders.get(chain);
4200
+ if (!provider) return null;
4201
+ return provider.getStatus();
4202
+ }
4203
+ // ========== Network Resilience (#202) ==========
4204
+ /**
4205
+ * Simple online connectivity check.
4206
+ * Returns true if at least one configured chain's RPC responds.
4207
+ */
4208
+ get isOnline() {
4209
+ return this._checkOnline();
4210
+ }
4211
+ async _checkOnline() {
4212
+ const chains = this.getConfiguredChains();
4213
+ if (chains.length === 0) return false;
4214
+ for (const chain of chains) {
4215
+ const config = this._normalizedChains.get(chain);
4216
+ if (!config) continue;
4217
+ try {
4218
+ const controller = new AbortController();
4219
+ const timeout = setTimeout(() => controller.abort(), 3e3);
4220
+ const response = await fetch(config.provider, {
4221
+ method: "POST",
4222
+ headers: { "Content-Type": "application/json" },
4223
+ body: JSON.stringify({ jsonrpc: "2.0", method: "eth_chainId", params: [], id: 1 }),
4224
+ signal: controller.signal
4225
+ });
4226
+ clearTimeout(timeout);
4227
+ if (response.ok) return true;
4228
+ } catch {
4229
+ }
4230
+ }
4231
+ return false;
4232
+ }
4233
+ /**
4234
+ * Wrap an async operation with the instance retry config (#202)
4235
+ */
4236
+ async _withRetry(fn) {
4237
+ if (this._retryConfig) {
4238
+ return withRetry(fn, this._retryConfig);
4239
+ }
4240
+ return fn();
2556
4241
  }
2557
4242
  };
2558
4243
  function formatTokenAmount(amount, decimals) {
@@ -2570,42 +4255,402 @@ function formatTokenAmount(amount, decimals) {
2570
4255
  return `${whole}.${trimmed}`;
2571
4256
  }
2572
4257
 
4258
+ // src/validation.ts
4259
+ var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
4260
+ var TON_RAW_RE = /^0:[0-9a-fA-F]{64}$/;
4261
+ var TRON_ADDRESS_RE = /^T[1-9A-HJ-NP-Za-km-z]{33}$/;
4262
+ var BASE58_CHARS = /^[1-9A-HJ-NP-Za-km-z]+$/;
4263
+ var BECH32_BTC_RE = /^bc1[a-zA-HJ-NP-Z0-9]{25,90}$/;
4264
+ var COSMOS_BECH32_RE = /^[a-z]+1[a-z0-9]{38,58}$/;
4265
+ function isBase58(s) {
4266
+ return BASE58_CHARS.test(s);
4267
+ }
4268
+ function validateEvm(address) {
4269
+ if (!EVM_ADDRESS_RE.test(address)) {
4270
+ const detected = detectFamily(address, "evm");
4271
+ if (detected) {
4272
+ return {
4273
+ valid: false,
4274
+ error: `Address appears to be a ${detected} address, not an EVM address`,
4275
+ detectedFamily: detected
4276
+ };
4277
+ }
4278
+ return {
4279
+ valid: false,
4280
+ error: "Invalid EVM address: must be 0x-prefixed, 40 hex characters"
4281
+ };
4282
+ }
4283
+ return {
4284
+ valid: true,
4285
+ normalized: address.toLowerCase()
4286
+ };
4287
+ }
4288
+ function validateTon(address) {
4289
+ if (TON_RAW_RE.test(address)) {
4290
+ return { valid: true, normalized: address.toLowerCase() };
4291
+ }
4292
+ const base64UrlRe = /^[A-Za-z0-9_\-+/=]{44,48}$/;
4293
+ if (base64UrlRe.test(address)) {
4294
+ return { valid: true, normalized: address };
4295
+ }
4296
+ const detected = detectFamily(address, "ton");
4297
+ if (detected) {
4298
+ return {
4299
+ valid: false,
4300
+ error: `Address appears to be a ${detected} address, not a TON address`,
4301
+ detectedFamily: detected
4302
+ };
4303
+ }
4304
+ return {
4305
+ valid: false,
4306
+ error: "Invalid TON address: must be raw format (0:<64 hex>) or user-friendly (48 chars base64)"
4307
+ };
4308
+ }
4309
+ function validateTron(address) {
4310
+ if (!TRON_ADDRESS_RE.test(address)) {
4311
+ const detected = detectFamily(address, "tron");
4312
+ if (detected) {
4313
+ return {
4314
+ valid: false,
4315
+ error: `Address appears to be a ${detected} address, not a TRON address`,
4316
+ detectedFamily: detected
4317
+ };
4318
+ }
4319
+ return {
4320
+ valid: false,
4321
+ error: "Invalid TRON address: must be T-prefixed base58check, 34 characters"
4322
+ };
4323
+ }
4324
+ return { valid: true, normalized: address };
4325
+ }
4326
+ function validateSvm(address) {
4327
+ if (TRON_ADDRESS_RE.test(address)) {
4328
+ return {
4329
+ valid: false,
4330
+ error: "Address appears to be a tron address, not a Solana address",
4331
+ detectedFamily: "tron"
4332
+ };
4333
+ }
4334
+ if (!isBase58(address) || address.length < 32 || address.length > 44) {
4335
+ const detected = detectFamily(address, "svm");
4336
+ if (detected) {
4337
+ return {
4338
+ valid: false,
4339
+ error: `Address appears to be a ${detected} address, not a Solana address`,
4340
+ detectedFamily: detected
4341
+ };
4342
+ }
4343
+ return {
4344
+ valid: false,
4345
+ error: "Invalid Solana address: must be base58, 32-44 characters"
4346
+ };
4347
+ }
4348
+ return { valid: true, normalized: address };
4349
+ }
4350
+ function validateBtc(address) {
4351
+ if (BECH32_BTC_RE.test(address)) {
4352
+ return { valid: true, normalized: address.toLowerCase() };
4353
+ }
4354
+ if ((address.startsWith("1") || address.startsWith("3")) && isBase58(address)) {
4355
+ if (address.length >= 25 && address.length <= 34) {
4356
+ return { valid: true, normalized: address };
4357
+ }
4358
+ }
4359
+ const detected = detectFamily(address, "btc");
4360
+ if (detected) {
4361
+ return {
4362
+ valid: false,
4363
+ error: `Address appears to be a ${detected} address, not a Bitcoin address`,
4364
+ detectedFamily: detected
4365
+ };
4366
+ }
4367
+ return {
4368
+ valid: false,
4369
+ error: "Invalid Bitcoin address: must be bech32 (bc1...) or base58 (1... or 3...), 25-90 characters"
4370
+ };
4371
+ }
4372
+ function validateCosmos(address) {
4373
+ if (!COSMOS_BECH32_RE.test(address)) {
4374
+ const detected = detectFamily(address, "cosmos");
4375
+ if (detected) {
4376
+ return {
4377
+ valid: false,
4378
+ error: `Address appears to be a ${detected} address, not a Cosmos address`,
4379
+ detectedFamily: detected
4380
+ };
4381
+ }
4382
+ return {
4383
+ valid: false,
4384
+ error: "Invalid Cosmos address: must be bech32 with lowercase prefix"
4385
+ };
4386
+ }
4387
+ return { valid: true, normalized: address };
4388
+ }
4389
+ function detectFamily(address, exclude) {
4390
+ if (exclude !== "evm" && EVM_ADDRESS_RE.test(address)) return "evm";
4391
+ if (exclude !== "tron" && TRON_ADDRESS_RE.test(address)) return "tron";
4392
+ if (exclude !== "ton" && (TON_RAW_RE.test(address) || /^[A-Za-z0-9_\-+/=]{44,48}$/.test(address)))
4393
+ return "ton";
4394
+ if (exclude !== "btc" && (BECH32_BTC_RE.test(address) || address.startsWith("1") && isBase58(address) && address.length >= 25 && address.length <= 34))
4395
+ return "btc";
4396
+ if (exclude !== "svm" && exclude !== "tron" && isBase58(address) && address.length >= 32 && address.length <= 44 && !address.startsWith("T"))
4397
+ return "svm";
4398
+ return void 0;
4399
+ }
4400
+ var VALIDATORS = {
4401
+ evm: validateEvm,
4402
+ ton: validateTon,
4403
+ tron: validateTron,
4404
+ svm: validateSvm,
4405
+ btc: validateBtc,
4406
+ spark: validateBtc,
4407
+ // Spark uses Bitcoin addresses
4408
+ cosmos: validateCosmos
4409
+ };
4410
+ function validatePaymentAddress(address, family) {
4411
+ if (!address || typeof address !== "string") {
4412
+ return { valid: false, error: "Address is required" };
4413
+ }
4414
+ const trimmed = address.trim();
4415
+ if (trimmed.length === 0) {
4416
+ return { valid: false, error: "Address is required" };
4417
+ }
4418
+ const validator = VALIDATORS[family];
4419
+ if (!validator) {
4420
+ return { valid: false, error: `Unsupported chain family: ${family}` };
4421
+ }
4422
+ return validator(trimmed);
4423
+ }
4424
+
4425
+ // src/bridge.ts
4426
+ import {
4427
+ Usdt0Bridge,
4428
+ supportsBridging as supportsBridging2,
4429
+ getBridgeableChains as getBridgeableChains2
4430
+ } from "@t402/evm";
4431
+
4432
+ // src/bridge-tracker.ts
4433
+ var LAYERZERO_SCAN_API = "https://scan.layerzero-api.com/v1";
4434
+ var BridgeTracker = class {
4435
+ apiBaseUrl;
4436
+ constructor(config) {
4437
+ this.apiBaseUrl = config?.apiBaseUrl ?? LAYERZERO_SCAN_API;
4438
+ }
4439
+ /** Get current status of a bridge message */
4440
+ async getStatus(txHash) {
4441
+ const response = await fetch(`${this.apiBaseUrl}/messages/tx/${txHash}`);
4442
+ if (!response.ok) {
4443
+ if (response.status === 404) return { status: "INFLIGHT" };
4444
+ throw new Error(`LayerZero API error: ${response.status}`);
4445
+ }
4446
+ const data = await response.json();
4447
+ return mapLayerZeroStatus(data);
4448
+ }
4449
+ /** Wait for delivery with polling */
4450
+ async waitForDelivery(txHash, options) {
4451
+ const timeout = options?.timeout ?? 6e5;
4452
+ const pollInterval = options?.pollInterval ?? 1e4;
4453
+ const startTime = Date.now();
4454
+ while (Date.now() - startTime < timeout) {
4455
+ const { status, dstTxHash } = await this.getStatus(txHash);
4456
+ options?.onStatusChange?.(status);
4457
+ if (status === "DELIVERED") {
4458
+ return {
4459
+ success: true,
4460
+ status,
4461
+ dstTxHash,
4462
+ srcTxHash: txHash,
4463
+ messageGuid: txHash
4464
+ };
4465
+ }
4466
+ if (status === "FAILED" || status === "BLOCKED") {
4467
+ return {
4468
+ success: false,
4469
+ status,
4470
+ srcTxHash: txHash,
4471
+ messageGuid: txHash,
4472
+ error: `Bridge ${status.toLowerCase()}`
4473
+ };
4474
+ }
4475
+ await new Promise((r) => setTimeout(r, pollInterval));
4476
+ }
4477
+ return {
4478
+ success: false,
4479
+ status: "INFLIGHT",
4480
+ srcTxHash: txHash,
4481
+ messageGuid: txHash,
4482
+ error: "Timeout waiting for delivery"
4483
+ };
4484
+ }
4485
+ };
4486
+ function mapLayerZeroStatus(data) {
4487
+ const obj = data;
4488
+ if (!obj) return { status: "INFLIGHT" };
4489
+ const messages = obj.messages ?? obj.data ?? [];
4490
+ const msg = Array.isArray(messages) ? messages[0] : messages;
4491
+ if (!msg) return { status: "INFLIGHT" };
4492
+ const lzStatus = (msg.status ?? msg.msgStatus ?? "").toUpperCase();
4493
+ if (lzStatus === "DELIVERED" || lzStatus === "DESTINATION_FINALIZED") {
4494
+ return { status: "DELIVERED", dstTxHash: msg.dstTxHash };
4495
+ }
4496
+ if (lzStatus === "FAILED") return { status: "FAILED" };
4497
+ if (lzStatus === "BLOCKED") return { status: "BLOCKED" };
4498
+ if (lzStatus.includes("CONFIRM")) return { status: "CONFIRMING" };
4499
+ return { status: "INFLIGHT" };
4500
+ }
4501
+
2573
4502
  // src/bridge.ts
2574
- import { Usdt0Bridge, supportsBridging as supportsBridging2, getBridgeableChains as getBridgeableChains2 } from "@t402/evm";
4503
+ var jsonRpcId = 1;
4504
+ async function jsonRpcCall(rpcUrl, method, params) {
4505
+ const id = jsonRpcId++;
4506
+ const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
4507
+ const res = await fetch(rpcUrl, {
4508
+ method: "POST",
4509
+ headers: { "Content-Type": "application/json" },
4510
+ body
4511
+ });
4512
+ if (!res.ok) {
4513
+ throw new Error(`JSON-RPC request failed: ${res.status} ${res.statusText}`);
4514
+ }
4515
+ const json = await res.json();
4516
+ if (json.error) {
4517
+ throw new Error(`JSON-RPC error ${json.error.code}: ${json.error.message}`);
4518
+ }
4519
+ return json.result;
4520
+ }
4521
+ var KNOWN_SELECTORS = {
4522
+ // ERC-20
4523
+ balanceOf: "0x70a08231",
4524
+ allowance: "0xdd62ed3e",
4525
+ approve: "0x095ea7b3",
4526
+ transfer: "0xa9059cbb",
4527
+ // OFT / LayerZero
4528
+ quoteSend: "0x0d35b415",
4529
+ send: "0xc7c7f5b3"
4530
+ };
4531
+ function encodeUint256(value) {
4532
+ return value.toString(16).padStart(64, "0");
4533
+ }
4534
+ function encodeAddress(addr) {
4535
+ const clean = addr.startsWith("0x") ? addr.slice(2) : addr;
4536
+ return clean.toLowerCase().padStart(64, "0");
4537
+ }
4538
+ function encodeFunctionCall(args) {
4539
+ const selector = KNOWN_SELECTORS[args.functionName];
4540
+ if (!selector) {
4541
+ throw new Error(`Unknown function: ${args.functionName}. Cannot encode without full ABI codec.`);
4542
+ }
4543
+ const fnArgs = args.args ?? [];
4544
+ let encoded = selector;
4545
+ for (const arg of fnArgs) {
4546
+ if (typeof arg === "bigint") {
4547
+ encoded += encodeUint256(arg);
4548
+ } else if (typeof arg === "string" && arg.startsWith("0x") && arg.length === 42) {
4549
+ encoded += encodeAddress(arg);
4550
+ } else if (typeof arg === "string" && arg.startsWith("0x")) {
4551
+ const clean = arg.slice(2);
4552
+ encoded += clean.padStart(64, "0");
4553
+ } else if (typeof arg === "number") {
4554
+ encoded += BigInt(arg).toString(16).padStart(64, "0");
4555
+ } else if (typeof arg === "object" && arg !== null) {
4556
+ const obj = arg;
4557
+ for (const val of Object.values(obj)) {
4558
+ if (typeof val === "bigint") {
4559
+ encoded += encodeUint256(val);
4560
+ } else if (typeof val === "string" && val.startsWith("0x")) {
4561
+ const clean = val.slice(2);
4562
+ encoded += clean.padStart(64, "0");
4563
+ } else if (typeof val === "number") {
4564
+ encoded += BigInt(val).toString(16).padStart(64, "0");
4565
+ }
4566
+ }
4567
+ } else {
4568
+ throw new Error(`Cannot encode argument of type ${typeof arg}`);
4569
+ }
4570
+ }
4571
+ return encoded;
4572
+ }
4573
+ function decodeFunctionResult(args, hex) {
4574
+ if (typeof hex !== "string") return hex;
4575
+ const data = hex.startsWith("0x") ? hex.slice(2) : hex;
4576
+ if (data.length === 0) return void 0;
4577
+ const word = data.slice(0, 64);
4578
+ const fnName = args.functionName;
4579
+ if (["balanceOf", "allowance", "totalSupply", "decimals", "nonces"].includes(fnName)) {
4580
+ return BigInt("0x" + word);
4581
+ }
4582
+ if (["approve", "transfer", "transferFrom"].includes(fnName)) {
4583
+ return BigInt("0x" + word) !== 0n;
4584
+ }
4585
+ return hex;
4586
+ }
4587
+ async function pollForReceipt(rpcUrl, hash, timeout) {
4588
+ const pollInterval = 2e3;
4589
+ const deadline = Date.now() + timeout;
4590
+ while (Date.now() < deadline) {
4591
+ const result = await jsonRpcCall(rpcUrl, "eth_getTransactionReceipt", [hash]);
4592
+ if (result) {
4593
+ return {
4594
+ status: result.status === "0x1" ? "success" : "reverted",
4595
+ transactionHash: result.transactionHash,
4596
+ logs: (result.logs ?? []).map((log) => ({
4597
+ address: log.address,
4598
+ topics: log.topics,
4599
+ data: log.data
4600
+ }))
4601
+ };
4602
+ }
4603
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
4604
+ }
4605
+ throw new Error(`Transaction receipt not found after ${timeout}ms: ${hash}`);
4606
+ }
2575
4607
  var WdkBridge = class {
2576
4608
  bridges = /* @__PURE__ */ new Map();
4609
+ tracker;
4610
+ constructor(trackerConfig) {
4611
+ this.tracker = new BridgeTracker(trackerConfig);
4612
+ }
2577
4613
  /**
2578
- * Create bridge signer adapter from WDK signer
4614
+ * Create bridge signer adapter from WDK signer.
4615
+ *
4616
+ * Uses JSON-RPC calls for readContract / waitForTransactionReceipt,
4617
+ * and delegates writeContract to the WDK signer's sendTransaction.
2579
4618
  */
2580
- createBridgeSigner(signer) {
4619
+ createBridgeSigner(signer, rpcUrl) {
2581
4620
  return {
2582
4621
  address: signer.address,
2583
- readContract: async (_args) => {
2584
- throw new Error(
2585
- "readContract not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
2586
- );
4622
+ readContract: async (args) => {
4623
+ const data = encodeFunctionCall(args);
4624
+ const result = await jsonRpcCall(rpcUrl, "eth_call", [{ to: args.address, data }, "latest"]);
4625
+ return decodeFunctionResult(args, result);
2587
4626
  },
2588
- writeContract: async (_args) => {
2589
- throw new Error(
2590
- "writeContract not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
2591
- );
4627
+ writeContract: async (args) => {
4628
+ const data = encodeFunctionCall(args);
4629
+ const { hash } = await signer.sendTransaction({
4630
+ to: args.address,
4631
+ data,
4632
+ value: args.value
4633
+ });
4634
+ return hash;
2592
4635
  },
2593
- waitForTransactionReceipt: async (_args) => {
2594
- throw new Error(
2595
- "waitForTransactionReceipt not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
2596
- );
4636
+ waitForTransactionReceipt: async (args) => {
4637
+ return pollForReceipt(rpcUrl, args.hash, 6e4);
2597
4638
  }
2598
4639
  };
2599
4640
  }
2600
4641
  /**
2601
4642
  * Get or create a bridge instance for a chain
4643
+ *
4644
+ * @param chain - Chain name (e.g., "arbitrum", "ethereum")
4645
+ * @param signer - WDK signer for the chain
4646
+ * @param rpcUrl - JSON-RPC endpoint URL for the chain
2602
4647
  */
2603
- getBridge(chain, signer) {
4648
+ getBridge(chain, signer, rpcUrl) {
2604
4649
  const cached = this.bridges.get(chain);
2605
4650
  if (cached) {
2606
4651
  return cached;
2607
4652
  }
2608
- const bridgeSigner = this.createBridgeSigner(signer);
4653
+ const bridgeSigner = this.createBridgeSigner(signer, rpcUrl);
2609
4654
  const bridge = new Usdt0Bridge(bridgeSigner, chain);
2610
4655
  this.bridges.set(chain, bridge);
2611
4656
  return bridge;
@@ -2633,6 +4678,59 @@ function createDirectBridge(signer, chain) {
2633
4678
  return new Usdt0Bridge(signer, chain);
2634
4679
  }
2635
4680
 
4681
+ // src/logger.ts
4682
+ var defaultLogger = {
4683
+ debug(msg, ctx) {
4684
+ if (ctx && Object.keys(ctx).length > 0) {
4685
+ console.debug(`[t402] ${msg}`, ctx);
4686
+ } else {
4687
+ console.debug(`[t402] ${msg}`);
4688
+ }
4689
+ },
4690
+ info(msg, ctx) {
4691
+ if (ctx && Object.keys(ctx).length > 0) {
4692
+ console.info(`[t402] ${msg}`, ctx);
4693
+ } else {
4694
+ console.info(`[t402] ${msg}`);
4695
+ }
4696
+ },
4697
+ warn(msg, ctx) {
4698
+ if (ctx && Object.keys(ctx).length > 0) {
4699
+ console.warn(`[t402] ${msg}`, ctx);
4700
+ } else {
4701
+ console.warn(`[t402] ${msg}`);
4702
+ }
4703
+ },
4704
+ error(msg, ctx) {
4705
+ if (ctx && Object.keys(ctx).length > 0) {
4706
+ console.error(`[t402] ${msg}`, ctx);
4707
+ } else {
4708
+ console.error(`[t402] ${msg}`);
4709
+ }
4710
+ }
4711
+ };
4712
+ var noopLogger = {
4713
+ debug() {
4714
+ },
4715
+ info() {
4716
+ },
4717
+ warn() {
4718
+ },
4719
+ error() {
4720
+ }
4721
+ };
4722
+ function createCorrelationId() {
4723
+ const bytes = new Uint8Array(8);
4724
+ if (typeof globalThis.crypto?.getRandomValues === "function") {
4725
+ globalThis.crypto.getRandomValues(bytes);
4726
+ } else {
4727
+ for (let i = 0; i < bytes.length; i++) {
4728
+ bytes[i] = Math.floor(Math.random() * 256);
4729
+ }
4730
+ }
4731
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
4732
+ }
4733
+
2636
4734
  // src/index.ts
2637
4735
  import {
2638
4736
  supportsBridging as supportsBridging3,
@@ -2730,6 +4828,575 @@ function getWalletModuleMinVersion(module) {
2730
4828
  return WDK_COMPATIBILITY.walletModuleVersions[module];
2731
4829
  }
2732
4830
 
4831
+ // src/idempotency.ts
4832
+ var InMemoryIdempotencyManager = class {
4833
+ _payments = /* @__PURE__ */ new Map();
4834
+ _nonces = /* @__PURE__ */ new Map();
4835
+ _recentTxHashes;
4836
+ _maxRecentTxHashes;
4837
+ /**
4838
+ * @param maxRecentTxHashes - Maximum number of recent tx hashes to track for dedup (default: 1000)
4839
+ */
4840
+ constructor(maxRecentTxHashes = 1e3) {
4841
+ this._recentTxHashes = /* @__PURE__ */ new Set();
4842
+ this._maxRecentTxHashes = maxRecentTxHashes;
4843
+ }
4844
+ async checkDuplicate(key) {
4845
+ return this._payments.has(key);
4846
+ }
4847
+ async recordPayment(key, receipt) {
4848
+ this._payments.set(key, receipt);
4849
+ if (receipt.txHash) {
4850
+ this._addTxHash(receipt.txHash);
4851
+ }
4852
+ }
4853
+ async getNonce(address, chain) {
4854
+ const key = this._nonceKey(address, chain);
4855
+ return this._nonces.get(key) ?? 0n;
4856
+ }
4857
+ async incrementNonce(address, chain) {
4858
+ const key = this._nonceKey(address, chain);
4859
+ const current = this._nonces.get(key) ?? 0n;
4860
+ const next = current + 1n;
4861
+ this._nonces.set(key, next);
4862
+ return next;
4863
+ }
4864
+ /**
4865
+ * Check if a transaction hash has been seen recently
4866
+ */
4867
+ hasTxHash(txHash) {
4868
+ return this._recentTxHashes.has(txHash.toLowerCase());
4869
+ }
4870
+ /**
4871
+ * Get a recorded payment by its idempotency key
4872
+ */
4873
+ getPayment(key) {
4874
+ return this._payments.get(key);
4875
+ }
4876
+ /**
4877
+ * Get the number of recorded payments
4878
+ */
4879
+ get size() {
4880
+ return this._payments.size;
4881
+ }
4882
+ /**
4883
+ * Clear all recorded payments and nonces
4884
+ */
4885
+ clear() {
4886
+ this._payments.clear();
4887
+ this._nonces.clear();
4888
+ this._recentTxHashes.clear();
4889
+ }
4890
+ _nonceKey(address, chain) {
4891
+ return `${chain}:${address.toLowerCase()}`;
4892
+ }
4893
+ _addTxHash(txHash) {
4894
+ const normalized = txHash.toLowerCase();
4895
+ if (this._recentTxHashes.size >= this._maxRecentTxHashes) {
4896
+ const first = this._recentTxHashes.values().next().value;
4897
+ if (first !== void 0) {
4898
+ this._recentTxHashes.delete(first);
4899
+ }
4900
+ }
4901
+ this._recentTxHashes.add(normalized);
4902
+ }
4903
+ };
4904
+ var NonceManager = class {
4905
+ _nonces = /* @__PURE__ */ new Map();
4906
+ /**
4907
+ * Get the current nonce for an address on a chain.
4908
+ * If no cached value exists, uses the provided fetcher to query on-chain.
4909
+ *
4910
+ * @param address - Wallet address
4911
+ * @param chain - Chain identifier
4912
+ * @param fetchOnChainNonce - Optional function to query the on-chain nonce
4913
+ */
4914
+ async getNonce(address, chain, fetchOnChainNonce) {
4915
+ const key = this._key(address, chain);
4916
+ const cached = this._nonces.get(key);
4917
+ if (cached !== void 0) {
4918
+ return cached;
4919
+ }
4920
+ if (fetchOnChainNonce) {
4921
+ const onChainNonce = await fetchOnChainNonce();
4922
+ this._nonces.set(key, onChainNonce);
4923
+ return onChainNonce;
4924
+ }
4925
+ return 0n;
4926
+ }
4927
+ /**
4928
+ * Increment the nonce after a successful signature/transaction
4929
+ */
4930
+ increment(address, chain) {
4931
+ const key = this._key(address, chain);
4932
+ const current = this._nonces.get(key) ?? 0n;
4933
+ const next = current + 1n;
4934
+ this._nonces.set(key, next);
4935
+ return next;
4936
+ }
4937
+ /**
4938
+ * Set the nonce to a specific value (e.g., after querying on-chain)
4939
+ */
4940
+ set(address, chain, nonce) {
4941
+ const key = this._key(address, chain);
4942
+ this._nonces.set(key, nonce);
4943
+ }
4944
+ /**
4945
+ * Reset the nonce for an address on a chain (forces re-fetch on next use)
4946
+ */
4947
+ reset(address, chain) {
4948
+ const key = this._key(address, chain);
4949
+ this._nonces.delete(key);
4950
+ }
4951
+ /**
4952
+ * Clear all cached nonces
4953
+ */
4954
+ clear() {
4955
+ this._nonces.clear();
4956
+ }
4957
+ _key(address, chain) {
4958
+ return `${chain}:${address.toLowerCase()}`;
4959
+ }
4960
+ };
4961
+ function generateIdempotencyKey(params) {
4962
+ return `${params.from.toLowerCase()}:${params.payTo.toLowerCase()}:${params.network}:${params.amount}:${params.url}`;
4963
+ }
4964
+
4965
+ // src/compliance.ts
4966
+ var ComplianceManager = class {
4967
+ _providers = [];
4968
+ _auditTrail = [];
4969
+ /**
4970
+ * Register a compliance provider
4971
+ */
4972
+ registerProvider(provider) {
4973
+ this._providers.push(provider);
4974
+ }
4975
+ /**
4976
+ * Run all registered providers against the given parameters.
4977
+ * Returns the first rejection, or `{ allowed: true }` if all pass.
4978
+ *
4979
+ * @param params - The transaction parameters to check
4980
+ * @param action - The type of action being performed (default: 'payment')
4981
+ */
4982
+ async check(params, action = "payment") {
4983
+ if (this._providers.length === 0) {
4984
+ const result2 = { allowed: true };
4985
+ this._recordEvent(action, params, result2);
4986
+ return result2;
4987
+ }
4988
+ for (const provider of this._providers) {
4989
+ const result2 = await provider.check(params);
4990
+ if (!result2.allowed) {
4991
+ this._recordEvent(action, params, result2);
4992
+ return result2;
4993
+ }
4994
+ }
4995
+ const result = { allowed: true };
4996
+ this._recordEvent(action, params, result);
4997
+ return result;
4998
+ }
4999
+ /**
5000
+ * Get the full audit trail of compliance checks
5001
+ */
5002
+ getAuditTrail() {
5003
+ return [...this._auditTrail];
5004
+ }
5005
+ /**
5006
+ * Clear the audit trail
5007
+ */
5008
+ clearAuditTrail() {
5009
+ this._auditTrail = [];
5010
+ }
5011
+ /**
5012
+ * Get the number of registered providers
5013
+ */
5014
+ get providerCount() {
5015
+ return this._providers.length;
5016
+ }
5017
+ _recordEvent(action, params, result) {
5018
+ this._auditTrail.push({
5019
+ timestamp: Date.now(),
5020
+ action,
5021
+ params,
5022
+ result
5023
+ });
5024
+ }
5025
+ };
5026
+ var BlacklistProvider = class {
5027
+ _addresses;
5028
+ constructor(addresses) {
5029
+ this._addresses = /* @__PURE__ */ new Set();
5030
+ if (addresses) {
5031
+ for (const addr of addresses) {
5032
+ this._addresses.add(addr.toLowerCase());
5033
+ }
5034
+ }
5035
+ }
5036
+ async check(params) {
5037
+ const fromLower = params.from.toLowerCase();
5038
+ const toLower = params.to.toLowerCase();
5039
+ if (this._addresses.has(fromLower)) {
5040
+ return { allowed: false, reason: `Address ${params.from} is blacklisted (sender)` };
5041
+ }
5042
+ if (this._addresses.has(toLower)) {
5043
+ return { allowed: false, reason: `Address ${params.to} is blacklisted (recipient)` };
5044
+ }
5045
+ return { allowed: true };
5046
+ }
5047
+ /**
5048
+ * Add an address to the blacklist
5049
+ */
5050
+ addAddress(address) {
5051
+ this._addresses.add(address.toLowerCase());
5052
+ }
5053
+ /**
5054
+ * Remove an address from the blacklist
5055
+ */
5056
+ removeAddress(address) {
5057
+ this._addresses.delete(address.toLowerCase());
5058
+ }
5059
+ /**
5060
+ * Check if an address is blacklisted
5061
+ */
5062
+ hasAddress(address) {
5063
+ return this._addresses.has(address.toLowerCase());
5064
+ }
5065
+ /**
5066
+ * Get the number of blacklisted addresses
5067
+ */
5068
+ get size() {
5069
+ return this._addresses.size;
5070
+ }
5071
+ };
5072
+ var AmountLimitProvider = class {
5073
+ _maxPerTransaction;
5074
+ _cumulativeAmounts = /* @__PURE__ */ new Map();
5075
+ _maxCumulative;
5076
+ /**
5077
+ * @param maxPerTransaction - Maximum amount per single transaction
5078
+ * @param maxCumulative - Optional maximum cumulative amount per address
5079
+ */
5080
+ constructor(maxPerTransaction, maxCumulative) {
5081
+ this._maxPerTransaction = maxPerTransaction;
5082
+ this._maxCumulative = maxCumulative;
5083
+ }
5084
+ async check(params) {
5085
+ if (params.amount > this._maxPerTransaction) {
5086
+ return {
5087
+ allowed: false,
5088
+ reason: `Amount ${params.amount} exceeds per-transaction limit of ${this._maxPerTransaction}`
5089
+ };
5090
+ }
5091
+ if (this._maxCumulative !== void 0) {
5092
+ const key = params.from.toLowerCase();
5093
+ const cumulative = (this._cumulativeAmounts.get(key) ?? 0n) + params.amount;
5094
+ if (cumulative > this._maxCumulative) {
5095
+ return {
5096
+ allowed: false,
5097
+ reason: `Cumulative amount ${cumulative} would exceed limit of ${this._maxCumulative}`
5098
+ };
5099
+ }
5100
+ this._cumulativeAmounts.set(key, cumulative);
5101
+ }
5102
+ return { allowed: true };
5103
+ }
5104
+ /**
5105
+ * Reset cumulative tracking for an address
5106
+ */
5107
+ resetCumulative(address) {
5108
+ this._cumulativeAmounts.delete(address.toLowerCase());
5109
+ }
5110
+ /**
5111
+ * Reset all cumulative tracking
5112
+ */
5113
+ resetAllCumulative() {
5114
+ this._cumulativeAmounts.clear();
5115
+ }
5116
+ };
5117
+
5118
+ // src/webhooks.ts
5119
+ var WebhookManager = class {
5120
+ _configs;
5121
+ _deliveryResults = [];
5122
+ _maxDeliveryHistory;
5123
+ /**
5124
+ * @param configs - Array of webhook endpoint configurations
5125
+ * @param maxDeliveryHistory - Maximum number of delivery results to retain (default: 100)
5126
+ */
5127
+ constructor(configs, maxDeliveryHistory = 100) {
5128
+ this._configs = configs;
5129
+ this._maxDeliveryHistory = maxDeliveryHistory;
5130
+ }
5131
+ /**
5132
+ * Send a webhook event to all subscribed endpoints
5133
+ *
5134
+ * @param event - Event type (e.g., 'payment.completed')
5135
+ * @param payload - Event payload data
5136
+ * @returns Array of delivery results for each endpoint
5137
+ */
5138
+ async send(event, payload) {
5139
+ const results = [];
5140
+ for (const config of this._configs) {
5141
+ if (config.events && config.events.length > 0 && !config.events.includes(event)) {
5142
+ continue;
5143
+ }
5144
+ const result = await this._deliver(config, event, payload);
5145
+ results.push(result);
5146
+ this._recordResult(result);
5147
+ }
5148
+ return results;
5149
+ }
5150
+ /**
5151
+ * Sign a payload with HMAC-SHA256
5152
+ *
5153
+ * @param payload - The payload to sign (will be JSON.stringify'd if not a string)
5154
+ * @param secret - The secret key
5155
+ * @returns Hex-encoded HMAC-SHA256 signature
5156
+ */
5157
+ signPayload(payload, secret) {
5158
+ const crypto = __require("crypto");
5159
+ const data = typeof payload === "string" ? payload : JSON.stringify(payload);
5160
+ return crypto.createHmac("sha256", secret).update(data).digest("hex");
5161
+ }
5162
+ /**
5163
+ * Verify an HMAC-SHA256 signature on a payload
5164
+ *
5165
+ * @param payload - The raw payload string
5166
+ * @param signature - The signature to verify
5167
+ * @param secret - The secret key
5168
+ * @returns True if the signature is valid
5169
+ */
5170
+ verifySignature(payload, signature, secret) {
5171
+ const expected = this.signPayload(payload, secret);
5172
+ if (expected.length !== signature.length) {
5173
+ return false;
5174
+ }
5175
+ const crypto = __require("crypto");
5176
+ return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(signature, "hex"));
5177
+ }
5178
+ /**
5179
+ * Get recent delivery results
5180
+ */
5181
+ getDeliveryResults() {
5182
+ return [...this._deliveryResults];
5183
+ }
5184
+ /**
5185
+ * Clear delivery history
5186
+ */
5187
+ clearDeliveryResults() {
5188
+ this._deliveryResults = [];
5189
+ }
5190
+ /**
5191
+ * Get the number of configured webhook endpoints
5192
+ */
5193
+ get endpointCount() {
5194
+ return this._configs.length;
5195
+ }
5196
+ async _deliver(config, event, payload) {
5197
+ const maxRetries = config.retries ?? 3;
5198
+ const body = JSON.stringify({ event, timestamp: (/* @__PURE__ */ new Date()).toISOString(), data: payload });
5199
+ const signature = this.signPayload(body, config.secret);
5200
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
5201
+ try {
5202
+ const response = await fetch(config.url, {
5203
+ method: "POST",
5204
+ headers: {
5205
+ "Content-Type": "application/json",
5206
+ "X-Webhook-Signature": signature,
5207
+ "X-Webhook-Event": event
5208
+ },
5209
+ body
5210
+ });
5211
+ if (response.ok) {
5212
+ return {
5213
+ url: config.url,
5214
+ success: true,
5215
+ statusCode: response.status,
5216
+ attempts: attempt
5217
+ };
5218
+ }
5219
+ if (response.status >= 400 && response.status < 500) {
5220
+ return {
5221
+ url: config.url,
5222
+ success: false,
5223
+ statusCode: response.status,
5224
+ error: `HTTP ${response.status}`,
5225
+ attempts: attempt
5226
+ };
5227
+ }
5228
+ if (attempt === maxRetries) {
5229
+ return {
5230
+ url: config.url,
5231
+ success: false,
5232
+ statusCode: response.status,
5233
+ error: `HTTP ${response.status} after ${maxRetries} attempts`,
5234
+ attempts: attempt
5235
+ };
5236
+ }
5237
+ await this._sleep(Math.min(1e3 * Math.pow(2, attempt - 1), 1e4));
5238
+ } catch (error) {
5239
+ if (attempt === maxRetries) {
5240
+ return {
5241
+ url: config.url,
5242
+ success: false,
5243
+ error: error instanceof Error ? error.message : String(error),
5244
+ attempts: attempt
5245
+ };
5246
+ }
5247
+ await this._sleep(Math.min(1e3 * Math.pow(2, attempt - 1), 1e4));
5248
+ }
5249
+ }
5250
+ return {
5251
+ url: config.url,
5252
+ success: false,
5253
+ error: "Max retries exceeded",
5254
+ attempts: maxRetries
5255
+ };
5256
+ }
5257
+ _recordResult(result) {
5258
+ this._deliveryResults.push(result);
5259
+ while (this._deliveryResults.length > this._maxDeliveryHistory) {
5260
+ this._deliveryResults.shift();
5261
+ }
5262
+ }
5263
+ _sleep(ms) {
5264
+ return new Promise((resolve) => setTimeout(resolve, ms));
5265
+ }
5266
+ };
5267
+
5268
+ // src/indexer.ts
5269
+ var WdkIndexerVerifier = class {
5270
+ endpoint;
5271
+ apiKey;
5272
+ timeout;
5273
+ constructor(config) {
5274
+ if (!config.endpoint) {
5275
+ throw new Error("Indexer endpoint is required");
5276
+ }
5277
+ this.endpoint = config.endpoint.replace(/\/$/, "");
5278
+ this.apiKey = config.apiKey;
5279
+ this.timeout = config.timeout ?? 1e4;
5280
+ }
5281
+ /**
5282
+ * Query a transaction across any supported chain
5283
+ */
5284
+ async queryTransaction(query) {
5285
+ if (!query.txHash) {
5286
+ throw new Error("Transaction hash is required");
5287
+ }
5288
+ if (!query.network) {
5289
+ throw new Error("Network is required");
5290
+ }
5291
+ const url = `${this.endpoint}/v1/transactions/${encodeURIComponent(query.network)}/${encodeURIComponent(query.txHash)}`;
5292
+ const headers = {
5293
+ "Content-Type": "application/json"
5294
+ };
5295
+ if (this.apiKey) {
5296
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
5297
+ }
5298
+ const controller = new AbortController();
5299
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5300
+ try {
5301
+ const response = await fetch(url, {
5302
+ method: "GET",
5303
+ headers,
5304
+ signal: controller.signal
5305
+ });
5306
+ if (!response.ok) {
5307
+ if (response.status === 404) {
5308
+ return {
5309
+ found: false,
5310
+ confirmed: false,
5311
+ from: "",
5312
+ to: "",
5313
+ amount: "0",
5314
+ token: ""
5315
+ };
5316
+ }
5317
+ throw new Error(`Indexer request failed: ${response.status} ${response.statusText}`);
5318
+ }
5319
+ const data = await response.json();
5320
+ return {
5321
+ found: true,
5322
+ confirmed: data.confirmed ?? data.status === "confirmed",
5323
+ from: data.from ?? "",
5324
+ to: data.to ?? "",
5325
+ amount: String(data.amount ?? data.value ?? "0"),
5326
+ token: data.token ?? data.tokenAddress ?? "",
5327
+ blockNumber: data.blockNumber ?? data.block_number,
5328
+ timestamp: data.timestamp ?? data.block_timestamp
5329
+ };
5330
+ } catch (error) {
5331
+ if (error.name === "AbortError") {
5332
+ throw new Error(`Indexer request timed out after ${this.timeout}ms`);
5333
+ }
5334
+ throw error;
5335
+ } finally {
5336
+ clearTimeout(timeoutId);
5337
+ }
5338
+ }
5339
+ /**
5340
+ * Verify a transaction matches expected payment parameters
5341
+ */
5342
+ async verifyPayment(query) {
5343
+ const result = await this.queryTransaction(query);
5344
+ if (!result.found) {
5345
+ return { verified: false, reason: "Transaction not found" };
5346
+ }
5347
+ if (!result.confirmed) {
5348
+ return { verified: false, reason: "Transaction not yet confirmed" };
5349
+ }
5350
+ if (query.expectedTo) {
5351
+ const normalizedExpected = query.expectedTo.toLowerCase();
5352
+ const normalizedActual = result.to.toLowerCase();
5353
+ if (normalizedActual !== normalizedExpected) {
5354
+ return {
5355
+ verified: false,
5356
+ reason: `Recipient mismatch: expected ${query.expectedTo}, got ${result.to}`
5357
+ };
5358
+ }
5359
+ }
5360
+ if (query.expectedAmount) {
5361
+ const expected = BigInt(query.expectedAmount);
5362
+ const actual = BigInt(result.amount);
5363
+ if (actual < expected) {
5364
+ return {
5365
+ verified: false,
5366
+ reason: `Amount insufficient: expected ${query.expectedAmount}, got ${result.amount}`
5367
+ };
5368
+ }
5369
+ }
5370
+ return { verified: true };
5371
+ }
5372
+ /**
5373
+ * Check indexer health
5374
+ */
5375
+ async healthCheck() {
5376
+ const controller = new AbortController();
5377
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
5378
+ try {
5379
+ const headers = {};
5380
+ if (this.apiKey) {
5381
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
5382
+ }
5383
+ const response = await fetch(`${this.endpoint}/health`, {
5384
+ method: "GET",
5385
+ headers,
5386
+ signal: controller.signal
5387
+ });
5388
+ return response.ok;
5389
+ } catch {
5390
+ return false;
5391
+ } finally {
5392
+ clearTimeout(timeoutId);
5393
+ }
5394
+ }
5395
+ };
5396
+ function createIndexerVerifier(config) {
5397
+ return new WdkIndexerVerifier(config);
5398
+ }
5399
+
2733
5400
  // src/hardware/types.ts
2734
5401
  var HardwareWalletErrorCode = /* @__PURE__ */ ((HardwareWalletErrorCode2) => {
2735
5402
  HardwareWalletErrorCode2["DEVICE_NOT_FOUND"] = "DEVICE_NOT_FOUND";
@@ -3352,25 +6019,178 @@ function isHardwareWalletSupported() {
3352
6019
  const support = detectHardwareWalletSupport();
3353
6020
  return support.ledger.webusb || support.ledger.webhid || support.ledger.bluetooth || support.trezor;
3354
6021
  }
6022
+
6023
+ // src/providers/moonpay.ts
6024
+ var NETWORK_TO_MOONPAY_CURRENCY = {
6025
+ "eip155:1": "usdt",
6026
+ "eip155:42161": "usdt_arbitrum",
6027
+ "eip155:137": "usdt_polygon",
6028
+ "eip155:8453": "usdt_base",
6029
+ "eip155:10": "usdt_optimism",
6030
+ "eip155:43114": "usdt_avalanche_c_chain",
6031
+ "eip155:56": "usdt_bsc"
6032
+ };
6033
+ var SUPPORTED_FIAT_CURRENCIES = ["USD", "EUR", "GBP"];
6034
+ var SUPPORTED_NETWORKS = Object.keys(NETWORK_TO_MOONPAY_CURRENCY);
6035
+ var BASE_URLS = {
6036
+ production: "https://buy.moonpay.com",
6037
+ sandbox: "https://buy-sandbox.moonpay.com"
6038
+ };
6039
+ var API_URLS = {
6040
+ production: "https://api.moonpay.com",
6041
+ sandbox: "https://api.moonpay.com"
6042
+ };
6043
+ var MoonpayOnRampProvider = class {
6044
+ name = "moonpay";
6045
+ _apiKey;
6046
+ _environment;
6047
+ constructor(config) {
6048
+ if (!config.apiKey) {
6049
+ throw new Error("Moonpay API key is required");
6050
+ }
6051
+ this._apiKey = config.apiKey;
6052
+ this._environment = config.environment ?? "production";
6053
+ }
6054
+ /**
6055
+ * Get the base widget URL for the current environment
6056
+ */
6057
+ get baseUrl() {
6058
+ return BASE_URLS[this._environment];
6059
+ }
6060
+ /**
6061
+ * Get the API base URL for the current environment
6062
+ */
6063
+ get apiUrl() {
6064
+ return API_URLS[this._environment];
6065
+ }
6066
+ /**
6067
+ * Get a quote for fiat-to-crypto conversion
6068
+ *
6069
+ * This method fetches a real-time quote from Moonpay.
6070
+ * Override `_fetchQuote` for testing.
6071
+ */
6072
+ async getQuote(params) {
6073
+ const currencyCode = this._getCurrencyCode(params.network);
6074
+ if (!currencyCode) {
6075
+ throw new Error(`Network "${params.network}" is not supported by Moonpay`);
6076
+ }
6077
+ if (params.fiatAmount <= 0) {
6078
+ throw new Error("fiatAmount must be greater than 0");
6079
+ }
6080
+ if (!SUPPORTED_FIAT_CURRENCIES.includes(params.fiatCurrency.toUpperCase())) {
6081
+ throw new Error(
6082
+ `Currency "${params.fiatCurrency}" is not supported. Supported: ${SUPPORTED_FIAT_CURRENCIES.join(", ")}`
6083
+ );
6084
+ }
6085
+ const quoteUrl = `${this.apiUrl}/v3/currencies/${currencyCode}/buy_quote?apiKey=${this._apiKey}&baseCurrencyAmount=${params.fiatAmount}&baseCurrencyCode=${params.fiatCurrency.toLowerCase()}`;
6086
+ const data = await this._fetchQuote(quoteUrl);
6087
+ return {
6088
+ fiatAmount: params.fiatAmount,
6089
+ fiatCurrency: params.fiatCurrency.toUpperCase(),
6090
+ cryptoAmount: String(data.quoteCurrencyAmount ?? "0"),
6091
+ cryptoCurrency: "USDT",
6092
+ exchangeRate: Number(data.quoteCurrencyPrice ?? 1),
6093
+ fees: {
6094
+ network: String(data.networkFeeAmount ?? "0"),
6095
+ service: String(data.feeAmount ?? "0"),
6096
+ total: String(data.totalFeeAmount ?? "0")
6097
+ },
6098
+ estimatedTime: 600
6099
+ // ~10 minutes typical for card purchases
6100
+ };
6101
+ }
6102
+ /**
6103
+ * Fetch quote from Moonpay API (override in tests)
6104
+ */
6105
+ async _fetchQuote(url) {
6106
+ const response = await fetch(url);
6107
+ if (!response.ok) {
6108
+ throw new Error(`Moonpay API error: ${response.status} ${response.statusText}`);
6109
+ }
6110
+ return response.json();
6111
+ }
6112
+ /**
6113
+ * Create a Moonpay widget URL for the user
6114
+ */
6115
+ createWidget(params) {
6116
+ const currencyCode = this._getCurrencyCode(params.network);
6117
+ if (!currencyCode) {
6118
+ throw new Error(`Network "${params.network}" is not supported by Moonpay`);
6119
+ }
6120
+ if (!params.walletAddress) {
6121
+ throw new Error("walletAddress is required");
6122
+ }
6123
+ if (params.fiatAmount <= 0) {
6124
+ throw new Error("fiatAmount must be greater than 0");
6125
+ }
6126
+ const queryParams = new URLSearchParams({
6127
+ apiKey: this._apiKey,
6128
+ currencyCode,
6129
+ baseCurrencyCode: params.fiatCurrency.toLowerCase(),
6130
+ baseCurrencyAmount: String(params.fiatAmount),
6131
+ walletAddress: params.walletAddress
6132
+ });
6133
+ if (params.redirectUrl) {
6134
+ queryParams.set("redirectURL", params.redirectUrl);
6135
+ }
6136
+ const widgetUrl = `${this.baseUrl}?${queryParams.toString()}`;
6137
+ const orderId = `mp_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
6138
+ const expiresAt = new Date(Date.now() + 30 * 60 * 1e3).toISOString();
6139
+ return { widgetUrl, orderId, expiresAt };
6140
+ }
6141
+ /**
6142
+ * Get supported fiat currencies
6143
+ */
6144
+ getSupportedCurrencies() {
6145
+ return [...SUPPORTED_FIAT_CURRENCIES];
6146
+ }
6147
+ /**
6148
+ * Get supported CAIP-2 networks
6149
+ */
6150
+ getSupportedNetworks() {
6151
+ return [...SUPPORTED_NETWORKS];
6152
+ }
6153
+ /**
6154
+ * Map CAIP-2 network to Moonpay currency code
6155
+ */
6156
+ _getCurrencyCode(network) {
6157
+ return NETWORK_TO_MOONPAY_CURRENCY[network];
6158
+ }
6159
+ };
6160
+ function getMoonpayCurrencyCode(network) {
6161
+ return NETWORK_TO_MOONPAY_CURRENCY[network];
6162
+ }
3355
6163
  export {
6164
+ AmountLimitProvider,
3356
6165
  BalanceCache,
3357
6166
  BalanceError,
6167
+ BlacklistProvider,
3358
6168
  BridgeError,
6169
+ BridgeTracker,
6170
+ CHAIN_REGISTRY,
3359
6171
  CHAIN_TOKENS,
3360
6172
  ChainError,
6173
+ ComplianceManager,
3361
6174
  DEFAULT_BALANCE_CACHE_CONFIG,
3362
6175
  DEFAULT_CACHE_CONFIG,
3363
6176
  DEFAULT_CHAINS,
3364
6177
  DEFAULT_RETRY_CONFIG,
3365
6178
  DEFAULT_RPC_ENDPOINTS,
6179
+ FailoverProvider,
3366
6180
  HardwareWalletError,
3367
6181
  HardwareWalletErrorCode,
6182
+ InMemoryIdempotencyManager,
6183
+ InMemoryReceiptStore,
3368
6184
  LAYERZERO_ENDPOINT_IDS,
3369
6185
  LedgerSigner,
3370
6186
  MockWDKSigner,
6187
+ MoonpayOnRampProvider,
6188
+ NonceManager,
3371
6189
  RPCError,
6190
+ SUPPORTED_WDK_RANGE,
3372
6191
  SignerError,
3373
6192
  SigningError,
6193
+ T402EventEmitter,
3374
6194
  T402WDK,
3375
6195
  TTLCache,
3376
6196
  TransactionError,
@@ -3389,28 +6209,72 @@ export {
3389
6209
  WDKTronSignerAdapter,
3390
6210
  WDK_COMPATIBILITY,
3391
6211
  WdkBridge,
6212
+ WdkIndexerVerifier,
6213
+ WebhookManager,
6214
+ buildVersionedTransaction,
3392
6215
  checkWalletEvmCompatibility,
3393
6216
  checkWdkCompatibility,
6217
+ compareSemver,
6218
+ createBackup,
6219
+ createCorrelationId,
3394
6220
  createDirectBridge,
6221
+ createFacilitatorSigners,
6222
+ createFailoverProvider,
6223
+ createIndexerVerifier,
3395
6224
  createLedgerSigner,
6225
+ createSIWxSigners,
3396
6226
  createTrezorSigner,
3397
6227
  createWDKSigner,
3398
6228
  createWDKSvmSigner,
3399
6229
  createWDKTonSigner,
3400
6230
  createWDKTronSigner,
6231
+ createWdkA2APaymentClient,
6232
+ createWdkMoneyParser,
6233
+ decryptSeed,
6234
+ defaultLogger,
6235
+ deriveATAAddress,
3401
6236
  detectHardwareWalletSupport,
6237
+ encryptSeed,
6238
+ generateIdempotencyKey,
3402
6239
  getBridgeableChains3 as getBridgeableChains,
3403
6240
  getChainFromNetwork,
3404
6241
  getChainId,
6242
+ getChainsByFamily,
6243
+ getJettonWalletAddress,
6244
+ getMoonpayCurrencyCode,
3405
6245
  getNetworkFromChain,
3406
6246
  getPreferredToken,
6247
+ getPricingProvider,
6248
+ getRecentPriorityFees,
6249
+ getRegistryByCaip2,
6250
+ getSecretManager,
6251
+ getTokenProgram,
6252
+ getTransferFee,
3407
6253
  getUsdt0Chains,
3408
6254
  getWalletModuleMinVersion,
3409
6255
  hasErrorCode,
3410
6256
  isHardwareWalletSupported,
6257
+ isPricingProviderRegistered,
3411
6258
  isWDKError,
6259
+ mapLayerZeroStatus,
6260
+ noopLogger,
3412
6261
  normalizeChainConfig,
6262
+ parseSemver,
6263
+ registerPricingProvider,
6264
+ registerSecretManager,
6265
+ resolveATA,
6266
+ resolveAssetForNetwork,
6267
+ resolveRpcUrl,
6268
+ rotateSeedPassword,
6269
+ satisfiesSemverRange,
3413
6270
  supportsBridging3 as supportsBridging,
6271
+ toAtomicUnits,
6272
+ toFacilitatorWdkSigner,
6273
+ toSIWxSigner,
6274
+ transferWithPriorityFee,
6275
+ validatePaymentAddress,
6276
+ verifyBackup,
6277
+ waitForJettonTransfer,
3414
6278
  withRetry,
3415
6279
  withTimeout,
3416
6280
  wrapError