@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.
- package/dist/cjs/adapters/index.d.ts +198 -1
- package/dist/cjs/adapters/index.js +255 -0
- package/dist/cjs/adapters/index.js.map +1 -1
- package/dist/cjs/adapters/svm-adapter.d.ts +146 -2
- package/dist/cjs/adapters/svm-adapter.js +255 -2
- package/dist/cjs/adapters/svm-adapter.js.map +1 -1
- package/dist/cjs/adapters/ton-adapter.d.ts +57 -2
- package/dist/cjs/adapters/ton-adapter.js +75 -2
- package/dist/cjs/adapters/ton-adapter.js.map +1 -1
- package/dist/cjs/adapters/tron-adapter.d.ts +57 -2
- package/dist/cjs/adapters/tron-adapter.js +101 -0
- package/dist/cjs/adapters/tron-adapter.js.map +1 -1
- package/dist/cjs/index-DnEI5M6d.d.ts +1798 -0
- package/dist/cjs/index.d.ts +702 -1118
- package/dist/cjs/index.js +3905 -246
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/integrations/index.d.ts +9 -0
- package/dist/cjs/integrations/index.js +249 -0
- package/dist/cjs/integrations/index.js.map +1 -0
- package/dist/cjs/testing/index.d.ts +62 -0
- package/dist/cjs/testing/index.js +129 -0
- package/dist/cjs/testing/index.js.map +1 -0
- package/dist/cjs/types-BwK8Xgvg.d.ts +967 -0
- package/dist/esm/adapters/index.d.mts +198 -1
- package/dist/esm/adapters/index.mjs +14 -3
- package/dist/esm/adapters/svm-adapter.d.mts +146 -2
- package/dist/esm/adapters/svm-adapter.mjs +18 -3
- package/dist/esm/adapters/ton-adapter.d.mts +57 -2
- package/dist/esm/adapters/ton-adapter.mjs +8 -3
- package/dist/esm/adapters/tron-adapter.d.mts +57 -2
- package/dist/esm/adapters/tron-adapter.mjs +2 -1
- package/dist/esm/chunk-2KWVW77U.mjs +353 -0
- package/dist/esm/chunk-2KWVW77U.mjs.map +1 -0
- package/dist/esm/chunk-7CG77QAN.mjs +153 -0
- package/dist/esm/chunk-7CG77QAN.mjs.map +1 -0
- package/dist/esm/chunk-BJTO5JO5.mjs +11 -0
- package/dist/esm/chunk-BJTO5JO5.mjs.map +1 -0
- package/dist/esm/{chunk-YWBJJV5M.mjs → chunk-KWX6CJIH.mjs} +72 -1
- package/dist/esm/chunk-KWX6CJIH.mjs.map +1 -0
- package/dist/esm/{chunk-HB2DGKQ3.mjs → chunk-QZKUU2O6.mjs} +102 -1
- package/dist/esm/chunk-QZKUU2O6.mjs.map +1 -0
- package/dist/esm/chunk-TVSNUSFZ.mjs +219 -0
- package/dist/esm/chunk-TVSNUSFZ.mjs.map +1 -0
- package/dist/esm/index-D5kvtDfm.d.mts +1798 -0
- package/dist/esm/index.d.mts +702 -1118
- package/dist/esm/index.mjs +2934 -70
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/integrations/index.d.mts +9 -0
- package/dist/esm/integrations/index.mjs +16 -0
- package/dist/esm/integrations/index.mjs.map +1 -0
- package/dist/esm/testing/index.d.mts +62 -0
- package/dist/esm/testing/index.mjs +101 -0
- package/dist/esm/testing/index.mjs.map +1 -0
- package/dist/esm/types-BwK8Xgvg.d.mts +967 -0
- package/package.json +69 -20
- package/dist/cjs/types-V7c-qhn6.d.ts +0 -489
- package/dist/esm/chunk-HB2DGKQ3.mjs.map +0 -1
- package/dist/esm/chunk-MCFHZSF7.mjs +0 -107
- package/dist/esm/chunk-MCFHZSF7.mjs.map +0 -1
- package/dist/esm/chunk-YWBJJV5M.mjs.map +0 -1
- package/dist/esm/types-V7c-qhn6.d.mts +0 -489
package/dist/esm/index.mjs
CHANGED
|
@@ -1,15 +1,296 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createWDKBtcSigner,
|
|
3
|
+
createWDKSparkSigner
|
|
4
|
+
} from "./chunk-7CG77QAN.mjs";
|
|
1
5
|
import {
|
|
2
6
|
WDKSvmSignerAdapter,
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
18
|
+
createWDKTonSigner,
|
|
19
|
+
getJettonWalletAddress,
|
|
20
|
+
waitForJettonTransfer
|
|
21
|
+
} from "./chunk-KWX6CJIH.mjs";
|
|
9
22
|
import {
|
|
10
23
|
WDKTronSignerAdapter,
|
|
11
24
|
createWDKTronSigner
|
|
12
|
-
} from "./chunk-
|
|
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:
|
|
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
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
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
|
-
*
|
|
2413
|
+
* Register a fiat on-ramp provider
|
|
1514
2414
|
*
|
|
1515
|
-
* @
|
|
1516
|
-
*
|
|
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
|
|
1519
|
-
if (!
|
|
1520
|
-
throw new WDKInitializationError(
|
|
1521
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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 &&
|
|
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 (!
|
|
2888
|
+
if (!this._wdkConstructor) {
|
|
1710
2889
|
this._initializationError = new WDKInitializationError("WDK not registered");
|
|
1711
2890
|
return;
|
|
1712
2891
|
}
|
|
1713
|
-
if (!
|
|
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
|
|
2899
|
+
let wdk = new this._wdkConstructor(this._seedPhrase);
|
|
1721
2900
|
for (const [chain, config] of this._normalizedChains) {
|
|
1722
2901
|
try {
|
|
1723
|
-
|
|
1724
|
-
|
|
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 (
|
|
2916
|
+
if (this._bridgeUsdt0Evm) {
|
|
1736
2917
|
try {
|
|
1737
|
-
wdk = wdk.registerProtocol("bridge-usdt0",
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
// ==========
|
|
3967
|
+
// ========== Lending Protocol ==========
|
|
2501
3968
|
/**
|
|
2502
|
-
* Check if
|
|
3969
|
+
* Check if the Aave lending protocol is registered and available
|
|
2503
3970
|
*/
|
|
2504
|
-
|
|
2505
|
-
return this.
|
|
3971
|
+
canBorrow() {
|
|
3972
|
+
return this._protocolModules.lendingAaveEvm !== void 0;
|
|
2506
3973
|
}
|
|
2507
3974
|
/**
|
|
2508
|
-
*
|
|
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
|
-
|
|
2511
|
-
|
|
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
|
-
|
|
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
|
|
4155
|
+
* Dispose of all resources held by this instance (#194).
|
|
2547
4156
|
*
|
|
2548
|
-
*
|
|
4157
|
+
* After disposal, any public method call will throw.
|
|
4158
|
+
* Safe to call multiple times.
|
|
2549
4159
|
*/
|
|
2550
4160
|
dispose() {
|
|
2551
|
-
this.
|
|
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
|
-
|
|
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 (
|
|
2584
|
-
|
|
2585
|
-
|
|
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 (
|
|
2589
|
-
|
|
2590
|
-
|
|
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 (
|
|
2594
|
-
|
|
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
|