@zubari/sdk 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{TransactionService-Djonkbp4.d.ts → TransactionService-BtWUjKt_.d.ts} +14 -2
- package/dist/{TransactionService-1Jt8ZRqO.d.mts → TransactionService-Lr_WS6iR.d.mts} +14 -2
- package/dist/{WalletManager-BJaLBfX5.d.ts → WalletManager-DQQwVkoa.d.ts} +52 -131
- package/dist/{WalletManager-pVFpurEi.d.mts → WalletManager-Sbpx4E1-.d.mts} +52 -131
- package/dist/{index-Da7SaweH.d.mts → contracts-B842YprC.d.mts} +152 -82
- package/dist/{index-ARbXbNI-.d.ts → contracts-s_CDIruh.d.ts} +152 -82
- package/dist/index.d.mts +65 -6
- package/dist/index.d.ts +65 -6
- package/dist/index.js +1268 -240
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1250 -240
- package/dist/index.mjs.map +1 -1
- package/dist/protocols/index.js +23 -5
- package/dist/protocols/index.js.map +1 -1
- package/dist/protocols/index.mjs +23 -5
- package/dist/protocols/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -4
- package/dist/react/index.d.ts +3 -4
- package/dist/react/index.js +1011 -151
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1010 -150
- package/dist/react/index.mjs.map +1 -1
- package/dist/services/index.d.mts +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +838 -112
- package/dist/services/index.js.map +1 -1
- package/dist/services/index.mjs +836 -110
- package/dist/services/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +3 -4
- package/dist/wallet/index.d.ts +3 -4
- package/dist/wallet/index.js +1042 -171
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +1041 -170
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +16 -14
package/dist/wallet/index.js
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
var ethers = require('ethers');
|
|
4
4
|
var bip39 = require('@scure/bip39');
|
|
5
5
|
var english = require('@scure/bip39/wordlists/english');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var secp256k1_js = require('@noble/curves/secp256k1.js');
|
|
7
|
+
var hmac_js = require('@noble/hashes/hmac.js');
|
|
8
|
+
var legacy_js = require('@noble/hashes/legacy.js');
|
|
9
|
+
var sha2_js = require('@noble/hashes/sha2.js');
|
|
10
|
+
var utils_js = require('@noble/hashes/utils.js');
|
|
8
11
|
var sha256 = require('@noble/hashes/sha256');
|
|
9
12
|
var ripemd160 = require('@noble/hashes/ripemd160');
|
|
10
13
|
var viem = require('viem');
|
|
@@ -31,7 +34,7 @@ var NETWORKS = {
|
|
|
31
34
|
chainId: 1,
|
|
32
35
|
coinType: 60,
|
|
33
36
|
// m/44'/60'
|
|
34
|
-
rpcUrl: "https://
|
|
37
|
+
rpcUrl: "https://ethereum-rpc.publicnode.com",
|
|
35
38
|
explorerUrl: "https://etherscan.io",
|
|
36
39
|
nativeCurrency: {
|
|
37
40
|
name: "Ether",
|
|
@@ -115,6 +118,38 @@ var TESTNET_NETWORKS = {
|
|
|
115
118
|
name: "Solana Devnet",
|
|
116
119
|
rpcUrl: "https://api.devnet.solana.com",
|
|
117
120
|
explorerUrl: "https://solscan.io?cluster=devnet"
|
|
121
|
+
},
|
|
122
|
+
tron: {
|
|
123
|
+
name: "TRON Nile Testnet",
|
|
124
|
+
chainId: 3448148188,
|
|
125
|
+
rpcUrl: "https://nile.trongrid.io",
|
|
126
|
+
explorerUrl: "https://nile.tronscan.org"
|
|
127
|
+
},
|
|
128
|
+
ton: {
|
|
129
|
+
name: "TON Testnet",
|
|
130
|
+
rpcUrl: "https://testnet.toncenter.com/api/v2",
|
|
131
|
+
explorerUrl: "https://testnet.tonscan.org"
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
var USDT_ADDRESSES = {
|
|
135
|
+
ethereum: {
|
|
136
|
+
mainnet: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
137
|
+
testnet: "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"
|
|
138
|
+
// Sepolia
|
|
139
|
+
},
|
|
140
|
+
tron: {
|
|
141
|
+
mainnet: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
|
|
142
|
+
testnet: "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf"
|
|
143
|
+
// Nile testnet
|
|
144
|
+
},
|
|
145
|
+
solana: {
|
|
146
|
+
mainnet: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
147
|
+
testnet: ""
|
|
148
|
+
// No official USDT on devnet
|
|
149
|
+
},
|
|
150
|
+
ton: {
|
|
151
|
+
mainnet: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
|
|
152
|
+
testnet: "kQD0GKBM8ZbryVk2aESmzfU6b9b_8era_IkvBSELujFZPsyy"
|
|
118
153
|
}
|
|
119
154
|
};
|
|
120
155
|
var DERIVATION_PATHS = {
|
|
@@ -140,37 +175,48 @@ function getNetworkConfig(network, isTestnet = false) {
|
|
|
140
175
|
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
141
176
|
var ZUBARI_CONTRACTS = {
|
|
142
177
|
testnet: {
|
|
143
|
-
// Ethereum Sepolia (11155111) -
|
|
144
|
-
|
|
145
|
-
|
|
178
|
+
// Ethereum Sepolia (11155111) - Updated 2025-01-18
|
|
179
|
+
// Treasury: 0xAC2e22B5a99F0123319644A9bF0DF4FD72c9b001
|
|
180
|
+
// Platform Fee: 10% (1000 bps)
|
|
181
|
+
registry: "0xcEd503aeD6E2F6884A7eAB4226D15477d863B084",
|
|
182
|
+
nft: "0xc61497530E08897CCf518cbF9DA1A327983192E1",
|
|
146
183
|
// ZubariNFT ERC-721 with payment
|
|
147
184
|
nft1155: "0x5e618B5bEaE1dc41369E7aa235Cc3b9245905192",
|
|
148
185
|
// Zubari1155 ERC-1155 multi-edition
|
|
149
|
-
marketplace: "
|
|
150
|
-
tips: "
|
|
151
|
-
|
|
186
|
+
marketplace: "0x64B8fC45bB669a1bD672bD5ab76f82B7EE3B2e0f",
|
|
187
|
+
tips: "0xFDc353edC63Cd3D4bba35bB43861369516a9Dc85",
|
|
188
|
+
// ZubariTips - 10% fee
|
|
189
|
+
subscriptions: "0x8C05F8aD2F295fB7f3596043a7c37C98A5F7fAB8",
|
|
190
|
+
// ZubariSubscription - 10% fee
|
|
152
191
|
subscriptionsV2: ZERO_ADDRESS,
|
|
153
|
-
|
|
154
|
-
|
|
192
|
+
subscriptionsSimple: "0x944f306e7d2e4f224dd660442EB65e4021b5eC24",
|
|
193
|
+
// Deployed 2025-01-26
|
|
194
|
+
creatorRegistry: ZERO_ADDRESS,
|
|
195
|
+
payouts: "0x804Fe503936E8b8d3D5Dbb62AF4fB6Fe7265Fb2c",
|
|
196
|
+
// ZubariPayouts
|
|
155
197
|
entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
156
198
|
paymaster: ZERO_ADDRESS,
|
|
157
199
|
// Deploy with: npx hardhat run deploy/deploy.ts --network ethereum-sepolia
|
|
158
200
|
accountFactory: ZERO_ADDRESS,
|
|
159
201
|
// Not yet deployed
|
|
160
|
-
usdt: "
|
|
161
|
-
// USDT on Sepolia
|
|
202
|
+
usdt: "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06",
|
|
203
|
+
// USDT on Sepolia (mintable test token)
|
|
162
204
|
weth: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"
|
|
163
205
|
},
|
|
164
206
|
mainnet: {
|
|
165
|
-
// Ethereum Mainnet (1)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
207
|
+
// Ethereum Mainnet (1) - Deployed 2025-01-22
|
|
208
|
+
// Owner/Treasury: Safe 0x436fE1eff6056aCc8c34d8ADe0C54B8AcF90DCAa
|
|
209
|
+
// Platform Fee: 10% (1000 bps)
|
|
210
|
+
registry: "0x1DA6880bc730e96cFA24d614D12012f9f81C3239",
|
|
211
|
+
nft: "0x19842D60a81bd65Bd9352A380C3b37dc2E0a5731",
|
|
212
|
+
nft1155: "0xDA824094c3ADdaC49e2480a699E2B21ca234BeD6",
|
|
213
|
+
marketplace: "0x8B0B3383644D0d374F4E047fC37e11F00f716b3A",
|
|
214
|
+
tips: "0x38D7Fc0592bCF094e1880c19a34f98c6A36b68D8",
|
|
215
|
+
subscriptions: "0xDA774d657B04Ab8744bfF09D18EeAce27E3F3DEa",
|
|
216
|
+
subscriptionsV2: "0x7abbaFe67941036bBF7dB7006855C55014d6012A",
|
|
217
|
+
subscriptionsSimple: "0xd0C07722a29D8aC7d137e59dCA114b031B4411E8",
|
|
218
|
+
creatorRegistry: "0xe5CE1Eb986f58BE42EEDFe5C18ee5956803b2BDC",
|
|
219
|
+
payouts: "0x74fc8cC0B5A92c90ae35caEB0E388Ea30424cc79",
|
|
174
220
|
entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
|
|
175
221
|
paymaster: ZERO_ADDRESS,
|
|
176
222
|
accountFactory: ZERO_ADDRESS,
|
|
@@ -234,14 +280,14 @@ var WdkApiClient = class {
|
|
|
234
280
|
/**
|
|
235
281
|
* Derive address for a specific chain using Tether WDK
|
|
236
282
|
*/
|
|
237
|
-
async deriveAddress(seed,
|
|
283
|
+
async deriveAddress(seed, chain2, network = "mainnet") {
|
|
238
284
|
try {
|
|
239
285
|
const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/derive-address`, {
|
|
240
286
|
method: "POST",
|
|
241
287
|
headers: {
|
|
242
288
|
"Content-Type": "application/json"
|
|
243
289
|
},
|
|
244
|
-
body: JSON.stringify({ seed, chain, network })
|
|
290
|
+
body: JSON.stringify({ seed, chain: chain2, network })
|
|
245
291
|
});
|
|
246
292
|
return await response.json();
|
|
247
293
|
} catch (error) {
|
|
@@ -254,7 +300,7 @@ var WdkApiClient = class {
|
|
|
254
300
|
/**
|
|
255
301
|
* Derive addresses for all chains using Tether WDK
|
|
256
302
|
*/
|
|
257
|
-
async deriveAllAddresses(seed, network = "
|
|
303
|
+
async deriveAllAddresses(seed, network = "mainnet") {
|
|
258
304
|
try {
|
|
259
305
|
const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/derive-all`, {
|
|
260
306
|
method: "POST",
|
|
@@ -274,14 +320,14 @@ var WdkApiClient = class {
|
|
|
274
320
|
/**
|
|
275
321
|
* Send a transaction on a specific chain using Tether WDK
|
|
276
322
|
*/
|
|
277
|
-
async sendTransaction(seed,
|
|
323
|
+
async sendTransaction(seed, chain2, to, amount, network = "mainnet") {
|
|
278
324
|
try {
|
|
279
325
|
const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/send`, {
|
|
280
326
|
method: "POST",
|
|
281
327
|
headers: {
|
|
282
328
|
"Content-Type": "application/json"
|
|
283
329
|
},
|
|
284
|
-
body: JSON.stringify({ seed, chain, to, amount, network })
|
|
330
|
+
body: JSON.stringify({ seed, chain: chain2, to, amount, network })
|
|
285
331
|
});
|
|
286
332
|
return await response.json();
|
|
287
333
|
} catch (error) {
|
|
@@ -295,14 +341,14 @@ var WdkApiClient = class {
|
|
|
295
341
|
* Get transaction history for an address on a specific chain
|
|
296
342
|
* Fetches from blockchain explorers (Etherscan, mempool.space, etc.)
|
|
297
343
|
*/
|
|
298
|
-
async getTransactionHistory(seed,
|
|
344
|
+
async getTransactionHistory(seed, chain2, network = "mainnet", limit = 10) {
|
|
299
345
|
try {
|
|
300
346
|
const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/history`, {
|
|
301
347
|
method: "POST",
|
|
302
348
|
headers: {
|
|
303
349
|
"Content-Type": "application/json"
|
|
304
350
|
},
|
|
305
|
-
body: JSON.stringify({ seed, chain, network, limit })
|
|
351
|
+
body: JSON.stringify({ seed, chain: chain2, network, limit })
|
|
306
352
|
});
|
|
307
353
|
return await response.json();
|
|
308
354
|
} catch (error) {
|
|
@@ -316,14 +362,14 @@ var WdkApiClient = class {
|
|
|
316
362
|
* Get transaction status by hash
|
|
317
363
|
* Fetches from blockchain explorers to check confirmation status
|
|
318
364
|
*/
|
|
319
|
-
async getTransactionStatus(txHash,
|
|
365
|
+
async getTransactionStatus(txHash, chain2, network = "mainnet") {
|
|
320
366
|
try {
|
|
321
367
|
const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/tx-status`, {
|
|
322
368
|
method: "POST",
|
|
323
369
|
headers: {
|
|
324
370
|
"Content-Type": "application/json"
|
|
325
371
|
},
|
|
326
|
-
body: JSON.stringify({ txHash, chain, network })
|
|
372
|
+
body: JSON.stringify({ txHash, chain: chain2, network })
|
|
327
373
|
});
|
|
328
374
|
return await response.json();
|
|
329
375
|
} catch (error) {
|
|
@@ -344,6 +390,589 @@ function getWdkApiClient(baseUrl) {
|
|
|
344
390
|
}
|
|
345
391
|
return wdkApiClient;
|
|
346
392
|
}
|
|
393
|
+
|
|
394
|
+
// node_modules/@scure/base/index.js
|
|
395
|
+
function isBytes(a) {
|
|
396
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
397
|
+
}
|
|
398
|
+
function isArrayOf(isString, arr) {
|
|
399
|
+
if (!Array.isArray(arr))
|
|
400
|
+
return false;
|
|
401
|
+
if (arr.length === 0)
|
|
402
|
+
return true;
|
|
403
|
+
if (isString) {
|
|
404
|
+
return arr.every((item) => typeof item === "string");
|
|
405
|
+
} else {
|
|
406
|
+
return arr.every((item) => Number.isSafeInteger(item));
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function afn(input) {
|
|
410
|
+
if (typeof input !== "function")
|
|
411
|
+
throw new Error("function expected");
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
function astr(label, input) {
|
|
415
|
+
if (typeof input !== "string")
|
|
416
|
+
throw new Error(`${label}: string expected`);
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
function anumber(n) {
|
|
420
|
+
if (!Number.isSafeInteger(n))
|
|
421
|
+
throw new Error(`invalid integer: ${n}`);
|
|
422
|
+
}
|
|
423
|
+
function aArr(input) {
|
|
424
|
+
if (!Array.isArray(input))
|
|
425
|
+
throw new Error("array expected");
|
|
426
|
+
}
|
|
427
|
+
function astrArr(label, input) {
|
|
428
|
+
if (!isArrayOf(true, input))
|
|
429
|
+
throw new Error(`${label}: array of strings expected`);
|
|
430
|
+
}
|
|
431
|
+
function anumArr(label, input) {
|
|
432
|
+
if (!isArrayOf(false, input))
|
|
433
|
+
throw new Error(`${label}: array of numbers expected`);
|
|
434
|
+
}
|
|
435
|
+
// @__NO_SIDE_EFFECTS__
|
|
436
|
+
function chain(...args) {
|
|
437
|
+
const id = (a) => a;
|
|
438
|
+
const wrap = (a, b) => (c) => a(b(c));
|
|
439
|
+
const encode = args.map((x) => x.encode).reduceRight(wrap, id);
|
|
440
|
+
const decode = args.map((x) => x.decode).reduce(wrap, id);
|
|
441
|
+
return { encode, decode };
|
|
442
|
+
}
|
|
443
|
+
// @__NO_SIDE_EFFECTS__
|
|
444
|
+
function alphabet(letters) {
|
|
445
|
+
const lettersA = typeof letters === "string" ? letters.split("") : letters;
|
|
446
|
+
const len = lettersA.length;
|
|
447
|
+
astrArr("alphabet", lettersA);
|
|
448
|
+
const indexes = new Map(lettersA.map((l, i) => [l, i]));
|
|
449
|
+
return {
|
|
450
|
+
encode: (digits) => {
|
|
451
|
+
aArr(digits);
|
|
452
|
+
return digits.map((i) => {
|
|
453
|
+
if (!Number.isSafeInteger(i) || i < 0 || i >= len)
|
|
454
|
+
throw new Error(`alphabet.encode: digit index outside alphabet "${i}". Allowed: ${letters}`);
|
|
455
|
+
return lettersA[i];
|
|
456
|
+
});
|
|
457
|
+
},
|
|
458
|
+
decode: (input) => {
|
|
459
|
+
aArr(input);
|
|
460
|
+
return input.map((letter) => {
|
|
461
|
+
astr("alphabet.decode", letter);
|
|
462
|
+
const i = indexes.get(letter);
|
|
463
|
+
if (i === void 0)
|
|
464
|
+
throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
|
|
465
|
+
return i;
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
// @__NO_SIDE_EFFECTS__
|
|
471
|
+
function join(separator = "") {
|
|
472
|
+
astr("join", separator);
|
|
473
|
+
return {
|
|
474
|
+
encode: (from) => {
|
|
475
|
+
astrArr("join.decode", from);
|
|
476
|
+
return from.join(separator);
|
|
477
|
+
},
|
|
478
|
+
decode: (to) => {
|
|
479
|
+
astr("join.decode", to);
|
|
480
|
+
return to.split(separator);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function convertRadix(data, from, to) {
|
|
485
|
+
if (from < 2)
|
|
486
|
+
throw new Error(`convertRadix: invalid from=${from}, base cannot be less than 2`);
|
|
487
|
+
if (to < 2)
|
|
488
|
+
throw new Error(`convertRadix: invalid to=${to}, base cannot be less than 2`);
|
|
489
|
+
aArr(data);
|
|
490
|
+
if (!data.length)
|
|
491
|
+
return [];
|
|
492
|
+
let pos = 0;
|
|
493
|
+
const res = [];
|
|
494
|
+
const digits = Array.from(data, (d) => {
|
|
495
|
+
anumber(d);
|
|
496
|
+
if (d < 0 || d >= from)
|
|
497
|
+
throw new Error(`invalid integer: ${d}`);
|
|
498
|
+
return d;
|
|
499
|
+
});
|
|
500
|
+
const dlen = digits.length;
|
|
501
|
+
while (true) {
|
|
502
|
+
let carry = 0;
|
|
503
|
+
let done = true;
|
|
504
|
+
for (let i = pos; i < dlen; i++) {
|
|
505
|
+
const digit = digits[i];
|
|
506
|
+
const fromCarry = from * carry;
|
|
507
|
+
const digitBase = fromCarry + digit;
|
|
508
|
+
if (!Number.isSafeInteger(digitBase) || fromCarry / from !== carry || digitBase - digit !== fromCarry) {
|
|
509
|
+
throw new Error("convertRadix: carry overflow");
|
|
510
|
+
}
|
|
511
|
+
const div = digitBase / to;
|
|
512
|
+
carry = digitBase % to;
|
|
513
|
+
const rounded = Math.floor(div);
|
|
514
|
+
digits[i] = rounded;
|
|
515
|
+
if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
|
|
516
|
+
throw new Error("convertRadix: carry overflow");
|
|
517
|
+
if (!done)
|
|
518
|
+
continue;
|
|
519
|
+
else if (!rounded)
|
|
520
|
+
pos = i;
|
|
521
|
+
else
|
|
522
|
+
done = false;
|
|
523
|
+
}
|
|
524
|
+
res.push(carry);
|
|
525
|
+
if (done)
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
for (let i = 0; i < data.length - 1 && data[i] === 0; i++)
|
|
529
|
+
res.push(0);
|
|
530
|
+
return res.reverse();
|
|
531
|
+
}
|
|
532
|
+
var gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
533
|
+
var radix2carry = /* @__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
|
|
534
|
+
var powers = /* @__PURE__ */ (() => {
|
|
535
|
+
let res = [];
|
|
536
|
+
for (let i = 0; i < 40; i++)
|
|
537
|
+
res.push(2 ** i);
|
|
538
|
+
return res;
|
|
539
|
+
})();
|
|
540
|
+
function convertRadix2(data, from, to, padding) {
|
|
541
|
+
aArr(data);
|
|
542
|
+
if (from <= 0 || from > 32)
|
|
543
|
+
throw new Error(`convertRadix2: wrong from=${from}`);
|
|
544
|
+
if (to <= 0 || to > 32)
|
|
545
|
+
throw new Error(`convertRadix2: wrong to=${to}`);
|
|
546
|
+
if (/* @__PURE__ */ radix2carry(from, to) > 32) {
|
|
547
|
+
throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${/* @__PURE__ */ radix2carry(from, to)}`);
|
|
548
|
+
}
|
|
549
|
+
let carry = 0;
|
|
550
|
+
let pos = 0;
|
|
551
|
+
const max = powers[from];
|
|
552
|
+
const mask = powers[to] - 1;
|
|
553
|
+
const res = [];
|
|
554
|
+
for (const n of data) {
|
|
555
|
+
anumber(n);
|
|
556
|
+
if (n >= max)
|
|
557
|
+
throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
|
|
558
|
+
carry = carry << from | n;
|
|
559
|
+
if (pos + from > 32)
|
|
560
|
+
throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
|
|
561
|
+
pos += from;
|
|
562
|
+
for (; pos >= to; pos -= to)
|
|
563
|
+
res.push((carry >> pos - to & mask) >>> 0);
|
|
564
|
+
const pow = powers[pos];
|
|
565
|
+
if (pow === void 0)
|
|
566
|
+
throw new Error("invalid carry");
|
|
567
|
+
carry &= pow - 1;
|
|
568
|
+
}
|
|
569
|
+
carry = carry << to - pos & mask;
|
|
570
|
+
if (!padding && pos >= from)
|
|
571
|
+
throw new Error("Excess padding");
|
|
572
|
+
if (!padding && carry > 0)
|
|
573
|
+
throw new Error(`Non-zero padding: ${carry}`);
|
|
574
|
+
if (padding && pos > 0)
|
|
575
|
+
res.push(carry >>> 0);
|
|
576
|
+
return res;
|
|
577
|
+
}
|
|
578
|
+
// @__NO_SIDE_EFFECTS__
|
|
579
|
+
function radix(num) {
|
|
580
|
+
anumber(num);
|
|
581
|
+
const _256 = 2 ** 8;
|
|
582
|
+
return {
|
|
583
|
+
encode: (bytes) => {
|
|
584
|
+
if (!isBytes(bytes))
|
|
585
|
+
throw new Error("radix.encode input should be Uint8Array");
|
|
586
|
+
return convertRadix(Array.from(bytes), _256, num);
|
|
587
|
+
},
|
|
588
|
+
decode: (digits) => {
|
|
589
|
+
anumArr("radix.decode", digits);
|
|
590
|
+
return Uint8Array.from(convertRadix(digits, num, _256));
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
// @__NO_SIDE_EFFECTS__
|
|
595
|
+
function radix2(bits, revPadding = false) {
|
|
596
|
+
anumber(bits);
|
|
597
|
+
if (/* @__PURE__ */ radix2carry(8, bits) > 32 || /* @__PURE__ */ radix2carry(bits, 8) > 32)
|
|
598
|
+
throw new Error("radix2: carry overflow");
|
|
599
|
+
return {
|
|
600
|
+
encode: (bytes) => {
|
|
601
|
+
if (!isBytes(bytes))
|
|
602
|
+
throw new Error("radix2.encode input should be Uint8Array");
|
|
603
|
+
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
|
|
604
|
+
},
|
|
605
|
+
decode: (digits) => {
|
|
606
|
+
anumArr("radix2.decode", digits);
|
|
607
|
+
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
function unsafeWrapper(fn) {
|
|
612
|
+
afn(fn);
|
|
613
|
+
return function(...args) {
|
|
614
|
+
try {
|
|
615
|
+
return fn.apply(null, args);
|
|
616
|
+
} catch (e) {
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function checksum(len, fn) {
|
|
621
|
+
anumber(len);
|
|
622
|
+
afn(fn);
|
|
623
|
+
return {
|
|
624
|
+
encode(data) {
|
|
625
|
+
if (!isBytes(data))
|
|
626
|
+
throw new Error("checksum.encode: input should be Uint8Array");
|
|
627
|
+
const sum = fn(data).slice(0, len);
|
|
628
|
+
const res = new Uint8Array(data.length + len);
|
|
629
|
+
res.set(data);
|
|
630
|
+
res.set(sum, data.length);
|
|
631
|
+
return res;
|
|
632
|
+
},
|
|
633
|
+
decode(data) {
|
|
634
|
+
if (!isBytes(data))
|
|
635
|
+
throw new Error("checksum.decode: input should be Uint8Array");
|
|
636
|
+
const payload = data.slice(0, -len);
|
|
637
|
+
const oldChecksum = data.slice(-len);
|
|
638
|
+
const newChecksum = fn(payload).slice(0, len);
|
|
639
|
+
for (let i = 0; i < len; i++)
|
|
640
|
+
if (newChecksum[i] !== oldChecksum[i])
|
|
641
|
+
throw new Error("Invalid checksum");
|
|
642
|
+
return payload;
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
var genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain(/* @__PURE__ */ radix(58), /* @__PURE__ */ alphabet(abc), /* @__PURE__ */ join(""));
|
|
647
|
+
var base58 = /* @__PURE__ */ genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
|
648
|
+
var createBase58check = (sha2563) => /* @__PURE__ */ chain(checksum(4, (data) => sha2563(sha2563(data))), base58);
|
|
649
|
+
var base58check = createBase58check;
|
|
650
|
+
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join(""));
|
|
651
|
+
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
652
|
+
function bech32Polymod(pre) {
|
|
653
|
+
const b = pre >> 25;
|
|
654
|
+
let chk = (pre & 33554431) << 5;
|
|
655
|
+
for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {
|
|
656
|
+
if ((b >> i & 1) === 1)
|
|
657
|
+
chk ^= POLYMOD_GENERATORS[i];
|
|
658
|
+
}
|
|
659
|
+
return chk;
|
|
660
|
+
}
|
|
661
|
+
function bechChecksum(prefix, words, encodingConst = 1) {
|
|
662
|
+
const len = prefix.length;
|
|
663
|
+
let chk = 1;
|
|
664
|
+
for (let i = 0; i < len; i++) {
|
|
665
|
+
const c = prefix.charCodeAt(i);
|
|
666
|
+
if (c < 33 || c > 126)
|
|
667
|
+
throw new Error(`Invalid prefix (${prefix})`);
|
|
668
|
+
chk = bech32Polymod(chk) ^ c >> 5;
|
|
669
|
+
}
|
|
670
|
+
chk = bech32Polymod(chk);
|
|
671
|
+
for (let i = 0; i < len; i++)
|
|
672
|
+
chk = bech32Polymod(chk) ^ prefix.charCodeAt(i) & 31;
|
|
673
|
+
for (let v of words)
|
|
674
|
+
chk = bech32Polymod(chk) ^ v;
|
|
675
|
+
for (let i = 0; i < 6; i++)
|
|
676
|
+
chk = bech32Polymod(chk);
|
|
677
|
+
chk ^= encodingConst;
|
|
678
|
+
return BECH_ALPHABET.encode(convertRadix2([chk % powers[30]], 30, 5, false));
|
|
679
|
+
}
|
|
680
|
+
// @__NO_SIDE_EFFECTS__
|
|
681
|
+
function genBech32(encoding) {
|
|
682
|
+
const ENCODING_CONST = 1 ;
|
|
683
|
+
const _words = /* @__PURE__ */ radix2(5);
|
|
684
|
+
const fromWords = _words.decode;
|
|
685
|
+
const toWords = _words.encode;
|
|
686
|
+
const fromWordsUnsafe = unsafeWrapper(fromWords);
|
|
687
|
+
function encode(prefix, words, limit = 90) {
|
|
688
|
+
astr("bech32.encode prefix", prefix);
|
|
689
|
+
if (isBytes(words))
|
|
690
|
+
words = Array.from(words);
|
|
691
|
+
anumArr("bech32.encode", words);
|
|
692
|
+
const plen = prefix.length;
|
|
693
|
+
if (plen === 0)
|
|
694
|
+
throw new TypeError(`Invalid prefix length ${plen}`);
|
|
695
|
+
const actualLength = plen + 7 + words.length;
|
|
696
|
+
if (limit !== false && actualLength > limit)
|
|
697
|
+
throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
|
|
698
|
+
const lowered = prefix.toLowerCase();
|
|
699
|
+
const sum = bechChecksum(lowered, words, ENCODING_CONST);
|
|
700
|
+
return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}`;
|
|
701
|
+
}
|
|
702
|
+
function decode(str, limit = 90) {
|
|
703
|
+
astr("bech32.decode input", str);
|
|
704
|
+
const slen = str.length;
|
|
705
|
+
if (slen < 8 || limit !== false && slen > limit)
|
|
706
|
+
throw new TypeError(`invalid string length: ${slen} (${str}). Expected (8..${limit})`);
|
|
707
|
+
const lowered = str.toLowerCase();
|
|
708
|
+
if (str !== lowered && str !== str.toUpperCase())
|
|
709
|
+
throw new Error(`String must be lowercase or uppercase`);
|
|
710
|
+
const sepIndex = lowered.lastIndexOf("1");
|
|
711
|
+
if (sepIndex === 0 || sepIndex === -1)
|
|
712
|
+
throw new Error(`Letter "1" must be present between prefix and data only`);
|
|
713
|
+
const prefix = lowered.slice(0, sepIndex);
|
|
714
|
+
const data = lowered.slice(sepIndex + 1);
|
|
715
|
+
if (data.length < 6)
|
|
716
|
+
throw new Error("Data must be at least 6 characters long");
|
|
717
|
+
const words = BECH_ALPHABET.decode(data).slice(0, -6);
|
|
718
|
+
const sum = bechChecksum(prefix, words, ENCODING_CONST);
|
|
719
|
+
if (!data.endsWith(sum))
|
|
720
|
+
throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
|
|
721
|
+
return { prefix, words };
|
|
722
|
+
}
|
|
723
|
+
const decodeUnsafe = unsafeWrapper(decode);
|
|
724
|
+
function decodeToBytes(str) {
|
|
725
|
+
const { prefix, words } = decode(str, false);
|
|
726
|
+
return { prefix, words, bytes: fromWords(words) };
|
|
727
|
+
}
|
|
728
|
+
function encodeFromBytes(prefix, bytes) {
|
|
729
|
+
return encode(prefix, toWords(bytes));
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
encode,
|
|
733
|
+
decode,
|
|
734
|
+
encodeFromBytes,
|
|
735
|
+
decodeToBytes,
|
|
736
|
+
decodeUnsafe,
|
|
737
|
+
fromWords,
|
|
738
|
+
fromWordsUnsafe,
|
|
739
|
+
toWords
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
var bech32 = /* @__PURE__ */ genBech32();
|
|
743
|
+
|
|
744
|
+
// node_modules/@scure/bip32/index.js
|
|
745
|
+
var Point = secp256k1_js.secp256k1.Point;
|
|
746
|
+
var { Fn } = Point;
|
|
747
|
+
var base58check2 = createBase58check(sha2_js.sha256);
|
|
748
|
+
var MASTER_SECRET = Uint8Array.from("Bitcoin seed".split(""), (char) => char.charCodeAt(0));
|
|
749
|
+
var BITCOIN_VERSIONS = { private: 76066276, public: 76067358 };
|
|
750
|
+
var HARDENED_OFFSET = 2147483648;
|
|
751
|
+
var hash160 = (data) => legacy_js.ripemd160(sha2_js.sha256(data));
|
|
752
|
+
var fromU32 = (data) => utils_js.createView(data).getUint32(0, false);
|
|
753
|
+
var toU32 = (n) => {
|
|
754
|
+
if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) {
|
|
755
|
+
throw new Error("invalid number, should be from 0 to 2**32-1, got " + n);
|
|
756
|
+
}
|
|
757
|
+
const buf = new Uint8Array(4);
|
|
758
|
+
utils_js.createView(buf).setUint32(0, n, false);
|
|
759
|
+
return buf;
|
|
760
|
+
};
|
|
761
|
+
var HDKey = class _HDKey {
|
|
762
|
+
get fingerprint() {
|
|
763
|
+
if (!this.pubHash) {
|
|
764
|
+
throw new Error("No publicKey set!");
|
|
765
|
+
}
|
|
766
|
+
return fromU32(this.pubHash);
|
|
767
|
+
}
|
|
768
|
+
get identifier() {
|
|
769
|
+
return this.pubHash;
|
|
770
|
+
}
|
|
771
|
+
get pubKeyHash() {
|
|
772
|
+
return this.pubHash;
|
|
773
|
+
}
|
|
774
|
+
get privateKey() {
|
|
775
|
+
return this._privateKey || null;
|
|
776
|
+
}
|
|
777
|
+
get publicKey() {
|
|
778
|
+
return this._publicKey || null;
|
|
779
|
+
}
|
|
780
|
+
get privateExtendedKey() {
|
|
781
|
+
const priv = this._privateKey;
|
|
782
|
+
if (!priv) {
|
|
783
|
+
throw new Error("No private key");
|
|
784
|
+
}
|
|
785
|
+
return base58check2.encode(this.serialize(this.versions.private, utils_js.concatBytes(Uint8Array.of(0), priv)));
|
|
786
|
+
}
|
|
787
|
+
get publicExtendedKey() {
|
|
788
|
+
if (!this._publicKey) {
|
|
789
|
+
throw new Error("No public key");
|
|
790
|
+
}
|
|
791
|
+
return base58check2.encode(this.serialize(this.versions.public, this._publicKey));
|
|
792
|
+
}
|
|
793
|
+
static fromMasterSeed(seed, versions = BITCOIN_VERSIONS) {
|
|
794
|
+
utils_js.abytes(seed);
|
|
795
|
+
if (8 * seed.length < 128 || 8 * seed.length > 512) {
|
|
796
|
+
throw new Error("HDKey: seed length must be between 128 and 512 bits; 256 bits is advised, got " + seed.length);
|
|
797
|
+
}
|
|
798
|
+
const I = hmac_js.hmac(sha2_js.sha512, MASTER_SECRET, seed);
|
|
799
|
+
const privateKey = I.slice(0, 32);
|
|
800
|
+
const chainCode = I.slice(32);
|
|
801
|
+
return new _HDKey({ versions, chainCode, privateKey });
|
|
802
|
+
}
|
|
803
|
+
static fromExtendedKey(base58key, versions = BITCOIN_VERSIONS) {
|
|
804
|
+
const keyBuffer = base58check2.decode(base58key);
|
|
805
|
+
const keyView = utils_js.createView(keyBuffer);
|
|
806
|
+
const version = keyView.getUint32(0, false);
|
|
807
|
+
const opt = {
|
|
808
|
+
versions,
|
|
809
|
+
depth: keyBuffer[4],
|
|
810
|
+
parentFingerprint: keyView.getUint32(5, false),
|
|
811
|
+
index: keyView.getUint32(9, false),
|
|
812
|
+
chainCode: keyBuffer.slice(13, 45)
|
|
813
|
+
};
|
|
814
|
+
const key = keyBuffer.slice(45);
|
|
815
|
+
const isPriv = key[0] === 0;
|
|
816
|
+
if (version !== versions[isPriv ? "private" : "public"]) {
|
|
817
|
+
throw new Error("Version mismatch");
|
|
818
|
+
}
|
|
819
|
+
if (isPriv) {
|
|
820
|
+
return new _HDKey({ ...opt, privateKey: key.slice(1) });
|
|
821
|
+
} else {
|
|
822
|
+
return new _HDKey({ ...opt, publicKey: key });
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
static fromJSON(json) {
|
|
826
|
+
return _HDKey.fromExtendedKey(json.xpriv);
|
|
827
|
+
}
|
|
828
|
+
versions;
|
|
829
|
+
depth = 0;
|
|
830
|
+
index = 0;
|
|
831
|
+
chainCode = null;
|
|
832
|
+
parentFingerprint = 0;
|
|
833
|
+
_privateKey;
|
|
834
|
+
_publicKey;
|
|
835
|
+
pubHash;
|
|
836
|
+
constructor(opt) {
|
|
837
|
+
if (!opt || typeof opt !== "object") {
|
|
838
|
+
throw new Error("HDKey.constructor must not be called directly");
|
|
839
|
+
}
|
|
840
|
+
this.versions = opt.versions || BITCOIN_VERSIONS;
|
|
841
|
+
this.depth = opt.depth || 0;
|
|
842
|
+
this.chainCode = opt.chainCode || null;
|
|
843
|
+
this.index = opt.index || 0;
|
|
844
|
+
this.parentFingerprint = opt.parentFingerprint || 0;
|
|
845
|
+
if (!this.depth) {
|
|
846
|
+
if (this.parentFingerprint || this.index) {
|
|
847
|
+
throw new Error("HDKey: zero depth with non-zero index/parent fingerprint");
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (this.depth > 255) {
|
|
851
|
+
throw new Error("HDKey: depth exceeds the serializable value 255");
|
|
852
|
+
}
|
|
853
|
+
if (opt.publicKey && opt.privateKey) {
|
|
854
|
+
throw new Error("HDKey: publicKey and privateKey at same time.");
|
|
855
|
+
}
|
|
856
|
+
if (opt.privateKey) {
|
|
857
|
+
if (!secp256k1_js.secp256k1.utils.isValidSecretKey(opt.privateKey))
|
|
858
|
+
throw new Error("Invalid private key");
|
|
859
|
+
this._privateKey = opt.privateKey;
|
|
860
|
+
this._publicKey = secp256k1_js.secp256k1.getPublicKey(opt.privateKey, true);
|
|
861
|
+
} else if (opt.publicKey) {
|
|
862
|
+
this._publicKey = Point.fromBytes(opt.publicKey).toBytes(true);
|
|
863
|
+
} else {
|
|
864
|
+
throw new Error("HDKey: no public or private key provided");
|
|
865
|
+
}
|
|
866
|
+
this.pubHash = hash160(this._publicKey);
|
|
867
|
+
}
|
|
868
|
+
derive(path) {
|
|
869
|
+
if (!/^[mM]'?/.test(path)) {
|
|
870
|
+
throw new Error('Path must start with "m" or "M"');
|
|
871
|
+
}
|
|
872
|
+
if (/^[mM]'?$/.test(path)) {
|
|
873
|
+
return this;
|
|
874
|
+
}
|
|
875
|
+
const parts = path.replace(/^[mM]'?\//, "").split("/");
|
|
876
|
+
let child = this;
|
|
877
|
+
for (const c of parts) {
|
|
878
|
+
const m = /^(\d+)('?)$/.exec(c);
|
|
879
|
+
const m1 = m && m[1];
|
|
880
|
+
if (!m || m.length !== 3 || typeof m1 !== "string")
|
|
881
|
+
throw new Error("invalid child index: " + c);
|
|
882
|
+
let idx = +m1;
|
|
883
|
+
if (!Number.isSafeInteger(idx) || idx >= HARDENED_OFFSET) {
|
|
884
|
+
throw new Error("Invalid index");
|
|
885
|
+
}
|
|
886
|
+
if (m[2] === "'") {
|
|
887
|
+
idx += HARDENED_OFFSET;
|
|
888
|
+
}
|
|
889
|
+
child = child.deriveChild(idx);
|
|
890
|
+
}
|
|
891
|
+
return child;
|
|
892
|
+
}
|
|
893
|
+
deriveChild(index) {
|
|
894
|
+
if (!this._publicKey || !this.chainCode) {
|
|
895
|
+
throw new Error("No publicKey or chainCode set");
|
|
896
|
+
}
|
|
897
|
+
let data = toU32(index);
|
|
898
|
+
if (index >= HARDENED_OFFSET) {
|
|
899
|
+
const priv = this._privateKey;
|
|
900
|
+
if (!priv) {
|
|
901
|
+
throw new Error("Could not derive hardened child key");
|
|
902
|
+
}
|
|
903
|
+
data = utils_js.concatBytes(Uint8Array.of(0), priv, data);
|
|
904
|
+
} else {
|
|
905
|
+
data = utils_js.concatBytes(this._publicKey, data);
|
|
906
|
+
}
|
|
907
|
+
const I = hmac_js.hmac(sha2_js.sha512, this.chainCode, data);
|
|
908
|
+
const childTweak = I.slice(0, 32);
|
|
909
|
+
const chainCode = I.slice(32);
|
|
910
|
+
if (!secp256k1_js.secp256k1.utils.isValidSecretKey(childTweak)) {
|
|
911
|
+
throw new Error("Tweak bigger than curve order");
|
|
912
|
+
}
|
|
913
|
+
const opt = {
|
|
914
|
+
versions: this.versions,
|
|
915
|
+
chainCode,
|
|
916
|
+
depth: this.depth + 1,
|
|
917
|
+
parentFingerprint: this.fingerprint,
|
|
918
|
+
index
|
|
919
|
+
};
|
|
920
|
+
const ctweak = Fn.fromBytes(childTweak);
|
|
921
|
+
try {
|
|
922
|
+
if (this._privateKey) {
|
|
923
|
+
const added = Fn.create(Fn.fromBytes(this._privateKey) + ctweak);
|
|
924
|
+
if (!Fn.isValidNot0(added)) {
|
|
925
|
+
throw new Error("The tweak was out of range or the resulted private key is invalid");
|
|
926
|
+
}
|
|
927
|
+
opt.privateKey = Fn.toBytes(added);
|
|
928
|
+
} else {
|
|
929
|
+
const added = Point.fromBytes(this._publicKey).add(Point.BASE.multiply(ctweak));
|
|
930
|
+
if (added.equals(Point.ZERO)) {
|
|
931
|
+
throw new Error("The tweak was equal to negative P, which made the result key invalid");
|
|
932
|
+
}
|
|
933
|
+
opt.publicKey = added.toBytes(true);
|
|
934
|
+
}
|
|
935
|
+
return new _HDKey(opt);
|
|
936
|
+
} catch (err) {
|
|
937
|
+
return this.deriveChild(index + 1);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
sign(hash) {
|
|
941
|
+
if (!this._privateKey) {
|
|
942
|
+
throw new Error("No privateKey set!");
|
|
943
|
+
}
|
|
944
|
+
utils_js.abytes(hash, 32);
|
|
945
|
+
return secp256k1_js.secp256k1.sign(hash, this._privateKey, { prehash: false });
|
|
946
|
+
}
|
|
947
|
+
verify(hash, signature) {
|
|
948
|
+
utils_js.abytes(hash, 32);
|
|
949
|
+
utils_js.abytes(signature, 64);
|
|
950
|
+
if (!this._publicKey) {
|
|
951
|
+
throw new Error("No publicKey set!");
|
|
952
|
+
}
|
|
953
|
+
return secp256k1_js.secp256k1.verify(signature, hash, this._publicKey, { prehash: false });
|
|
954
|
+
}
|
|
955
|
+
wipePrivateData() {
|
|
956
|
+
if (this._privateKey) {
|
|
957
|
+
this._privateKey.fill(0);
|
|
958
|
+
this._privateKey = void 0;
|
|
959
|
+
}
|
|
960
|
+
return this;
|
|
961
|
+
}
|
|
962
|
+
toJSON() {
|
|
963
|
+
return {
|
|
964
|
+
xpriv: this.privateExtendedKey,
|
|
965
|
+
xpub: this.publicExtendedKey
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
serialize(version, key) {
|
|
969
|
+
if (!this.chainCode) {
|
|
970
|
+
throw new Error("No chainCode set");
|
|
971
|
+
}
|
|
972
|
+
utils_js.abytes(key, 33);
|
|
973
|
+
return utils_js.concatBytes(toU32(version), new Uint8Array([this.depth]), toU32(this.parentFingerprint), toU32(this.index), this.chainCode, key);
|
|
974
|
+
}
|
|
975
|
+
};
|
|
347
976
|
var DERIVATION_PATHS2 = {
|
|
348
977
|
ethereum: "m/44'/60'/0'/0/0",
|
|
349
978
|
bitcoin_mainnet: "m/84'/0'/0'/0/0",
|
|
@@ -357,10 +986,10 @@ function deriveEthereumAddress(seed) {
|
|
|
357
986
|
const hdNode = ethers.HDNodeWallet.fromPhrase(seed, void 0, DERIVATION_PATHS2.ethereum);
|
|
358
987
|
return hdNode.address;
|
|
359
988
|
}
|
|
360
|
-
function deriveBitcoinAddress(seed, network = "
|
|
989
|
+
function deriveBitcoinAddress(seed, network = "mainnet") {
|
|
361
990
|
try {
|
|
362
991
|
const seedBytes = bip39.mnemonicToSeedSync(seed);
|
|
363
|
-
const hdKey =
|
|
992
|
+
const hdKey = HDKey.fromMasterSeed(seedBytes);
|
|
364
993
|
const path = network === "testnet" ? DERIVATION_PATHS2.bitcoin_testnet : DERIVATION_PATHS2.bitcoin_mainnet;
|
|
365
994
|
const child = hdKey.derive(path);
|
|
366
995
|
if (!child.publicKey) {
|
|
@@ -368,10 +997,10 @@ function deriveBitcoinAddress(seed, network = "testnet") {
|
|
|
368
997
|
}
|
|
369
998
|
const pubKeyHash = ripemd160.ripemd160(sha256.sha256(child.publicKey));
|
|
370
999
|
const witnessVersion = 0;
|
|
371
|
-
const words =
|
|
1000
|
+
const words = bech32.toWords(pubKeyHash);
|
|
372
1001
|
words.unshift(witnessVersion);
|
|
373
1002
|
const hrp = network === "testnet" ? "tb" : "bc";
|
|
374
|
-
const address =
|
|
1003
|
+
const address = bech32.encode(hrp, words);
|
|
375
1004
|
return address;
|
|
376
1005
|
} catch (error) {
|
|
377
1006
|
console.error("Bitcoin address derivation failed:", error);
|
|
@@ -444,34 +1073,34 @@ function deriveTronAddress(seed) {
|
|
|
444
1073
|
for (let i = 0; i < 20; i++) {
|
|
445
1074
|
addressBytes[i + 1] = parseInt(ethAddressHex.slice(i * 2, i * 2 + 2), 16);
|
|
446
1075
|
}
|
|
447
|
-
const tronBase58check =
|
|
1076
|
+
const tronBase58check = base58check(sha256.sha256);
|
|
448
1077
|
return tronBase58check.encode(addressBytes);
|
|
449
1078
|
} catch (error) {
|
|
450
1079
|
console.error("TRON address derivation failed:", error);
|
|
451
1080
|
throw error;
|
|
452
1081
|
}
|
|
453
1082
|
}
|
|
454
|
-
function deriveSparkAddress(seed, network = "
|
|
1083
|
+
function deriveSparkAddress(seed, network = "mainnet") {
|
|
455
1084
|
try {
|
|
456
1085
|
const seedBytes = bip39.mnemonicToSeedSync(seed);
|
|
457
|
-
const hdKey =
|
|
1086
|
+
const hdKey = HDKey.fromMasterSeed(seedBytes);
|
|
458
1087
|
const child = hdKey.derive(DERIVATION_PATHS2.spark);
|
|
459
1088
|
if (!child.publicKey) {
|
|
460
1089
|
throw new Error("Failed to derive public key");
|
|
461
1090
|
}
|
|
462
1091
|
const pubKeyHash = ripemd160.ripemd160(sha256.sha256(child.publicKey));
|
|
463
1092
|
const witnessVersion = 0;
|
|
464
|
-
const words =
|
|
1093
|
+
const words = bech32.toWords(pubKeyHash);
|
|
465
1094
|
words.unshift(witnessVersion);
|
|
466
1095
|
const hrp = network === "testnet" ? "tsp" : "sp";
|
|
467
|
-
const address =
|
|
1096
|
+
const address = bech32.encode(hrp, words);
|
|
468
1097
|
return address;
|
|
469
1098
|
} catch (error) {
|
|
470
1099
|
console.error("Spark address derivation failed:", error);
|
|
471
1100
|
throw error;
|
|
472
1101
|
}
|
|
473
1102
|
}
|
|
474
|
-
async function deriveAllAddresses(seed, network = "
|
|
1103
|
+
async function deriveAllAddresses(seed, network = "mainnet") {
|
|
475
1104
|
const addresses = {
|
|
476
1105
|
ethereum: null,
|
|
477
1106
|
bitcoin: null,
|
|
@@ -525,6 +1154,60 @@ function generateSeedPhrase() {
|
|
|
525
1154
|
|
|
526
1155
|
// src/services/ZubariWdkService.ts
|
|
527
1156
|
var DEFAULT_API_URL2 = "https://ckgwifsxka.us-east-2.awsapprunner.com";
|
|
1157
|
+
var CHAIN_ERROR_MESSAGES = {
|
|
1158
|
+
ethereum: {
|
|
1159
|
+
"insufficient funds": "INSUFFICIENT_FUNDS",
|
|
1160
|
+
"nonce too low": "NONCE_TOO_LOW",
|
|
1161
|
+
"gas too low": "GAS_TOO_LOW",
|
|
1162
|
+
"replacement transaction underpriced": "GAS_TOO_LOW",
|
|
1163
|
+
"transaction underpriced": "GAS_TOO_LOW",
|
|
1164
|
+
"invalid address": "INVALID_ADDRESS"
|
|
1165
|
+
},
|
|
1166
|
+
bitcoin: {
|
|
1167
|
+
"insufficient funds": "INSUFFICIENT_FUNDS",
|
|
1168
|
+
"dust": "DUST_AMOUNT",
|
|
1169
|
+
"mempool": "MEMPOOL_FULL",
|
|
1170
|
+
"invalid address": "INVALID_ADDRESS"
|
|
1171
|
+
},
|
|
1172
|
+
solana: {
|
|
1173
|
+
"insufficient funds": "INSUFFICIENT_FUNDS",
|
|
1174
|
+
"invalid account": "INVALID_ADDRESS",
|
|
1175
|
+
"blockhash not found": "NETWORK_ERROR"
|
|
1176
|
+
},
|
|
1177
|
+
ton: {
|
|
1178
|
+
"insufficient funds": "INSUFFICIENT_FUNDS",
|
|
1179
|
+
"invalid address": "INVALID_ADDRESS"
|
|
1180
|
+
},
|
|
1181
|
+
tron: {
|
|
1182
|
+
"insufficient funds": "INSUFFICIENT_FUNDS",
|
|
1183
|
+
"invalid address": "INVALID_ADDRESS",
|
|
1184
|
+
"bandwidth": "GAS_TOO_LOW"
|
|
1185
|
+
},
|
|
1186
|
+
spark: {
|
|
1187
|
+
"insufficient funds": "INSUFFICIENT_FUNDS",
|
|
1188
|
+
"invoice expired": "TIMEOUT",
|
|
1189
|
+
"no route": "NETWORK_ERROR"
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
function parseChainError(chain2, errorMessage) {
|
|
1193
|
+
const errorLower = errorMessage.toLowerCase();
|
|
1194
|
+
const chainErrors = CHAIN_ERROR_MESSAGES[chain2];
|
|
1195
|
+
for (const [pattern, code] of Object.entries(chainErrors)) {
|
|
1196
|
+
if (errorLower.includes(pattern)) {
|
|
1197
|
+
return code;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
if (errorLower.includes("timeout") || errorLower.includes("timed out")) {
|
|
1201
|
+
return "TIMEOUT";
|
|
1202
|
+
}
|
|
1203
|
+
if (errorLower.includes("network") || errorLower.includes("connection")) {
|
|
1204
|
+
return "NETWORK_ERROR";
|
|
1205
|
+
}
|
|
1206
|
+
if (errorLower.includes("rejected") || errorLower.includes("denied")) {
|
|
1207
|
+
return "REJECTED";
|
|
1208
|
+
}
|
|
1209
|
+
return "UNKNOWN";
|
|
1210
|
+
}
|
|
528
1211
|
function isBrowser() {
|
|
529
1212
|
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
530
1213
|
}
|
|
@@ -548,7 +1231,7 @@ var ZubariWdkService = class {
|
|
|
548
1231
|
useNativeWdk = false;
|
|
549
1232
|
constructor(config = {}) {
|
|
550
1233
|
this.config = {
|
|
551
|
-
network: config.network || "
|
|
1234
|
+
network: config.network || "mainnet",
|
|
552
1235
|
apiUrl: config.apiUrl || process.env.NEXT_PUBLIC_API_URL || DEFAULT_API_URL2,
|
|
553
1236
|
forceApi: config.forceApi ?? false,
|
|
554
1237
|
timeout: config.timeout || 3e4
|
|
@@ -646,38 +1329,38 @@ var ZubariWdkService = class {
|
|
|
646
1329
|
* For Ethereum, falls back to local derivation if API fails.
|
|
647
1330
|
* For other chains, WDK API is required - no placeholder fallback.
|
|
648
1331
|
*/
|
|
649
|
-
async deriveAddress(seed,
|
|
1332
|
+
async deriveAddress(seed, chain2) {
|
|
650
1333
|
await this.initialize();
|
|
651
|
-
const path = this.getDerivationPath(
|
|
1334
|
+
const path = this.getDerivationPath(chain2);
|
|
652
1335
|
try {
|
|
653
|
-
const response = await this.apiClient.deriveAddress(seed,
|
|
1336
|
+
const response = await this.apiClient.deriveAddress(seed, chain2, this.config.network);
|
|
654
1337
|
if (response.success && response.address) {
|
|
655
1338
|
return {
|
|
656
|
-
chain,
|
|
1339
|
+
chain: chain2,
|
|
657
1340
|
address: response.address,
|
|
658
1341
|
path: response.path || path
|
|
659
1342
|
};
|
|
660
1343
|
}
|
|
661
1344
|
} catch (error) {
|
|
662
|
-
console.warn(`API address derivation failed for ${
|
|
663
|
-
if (
|
|
664
|
-
return this.deriveBrowserAddress(seed,
|
|
1345
|
+
console.warn(`API address derivation failed for ${chain2}:`, error);
|
|
1346
|
+
if (chain2 === "ethereum") {
|
|
1347
|
+
return this.deriveBrowserAddress(seed, chain2);
|
|
665
1348
|
}
|
|
666
1349
|
}
|
|
667
1350
|
if (this.useNativeWdk && this.nativeWdkService) {
|
|
668
1351
|
try {
|
|
669
1352
|
const wdk = this.nativeWdkService;
|
|
670
1353
|
await wdk.initialize(seed);
|
|
671
|
-
return await wdk.deriveAddress(
|
|
1354
|
+
return await wdk.deriveAddress(chain2);
|
|
672
1355
|
} catch (error) {
|
|
673
|
-
console.warn(`Native WDK address derivation failed for ${
|
|
1356
|
+
console.warn(`Native WDK address derivation failed for ${chain2}:`, error);
|
|
674
1357
|
}
|
|
675
1358
|
}
|
|
676
|
-
if (
|
|
677
|
-
return this.deriveBrowserAddress(seed,
|
|
1359
|
+
if (chain2 === "ethereum") {
|
|
1360
|
+
return this.deriveBrowserAddress(seed, chain2);
|
|
678
1361
|
}
|
|
679
1362
|
throw new Error(
|
|
680
|
-
`WDK API required for ${
|
|
1363
|
+
`WDK API required for ${chain2} address derivation. Ensure the backend is running.`
|
|
681
1364
|
);
|
|
682
1365
|
}
|
|
683
1366
|
/**
|
|
@@ -699,7 +1382,7 @@ var ZubariWdkService = class {
|
|
|
699
1382
|
}
|
|
700
1383
|
return null;
|
|
701
1384
|
};
|
|
702
|
-
|
|
1385
|
+
const addresses = {
|
|
703
1386
|
ethereum: extractAddress(response.addresses.ethereum),
|
|
704
1387
|
bitcoin: extractAddress(response.addresses.bitcoin),
|
|
705
1388
|
ton: extractAddress(response.addresses.ton),
|
|
@@ -707,6 +1390,14 @@ var ZubariWdkService = class {
|
|
|
707
1390
|
solana: extractAddress(response.addresses.solana),
|
|
708
1391
|
spark: extractAddress(response.addresses.spark)
|
|
709
1392
|
};
|
|
1393
|
+
if (!addresses.spark) {
|
|
1394
|
+
try {
|
|
1395
|
+
addresses.spark = deriveSparkAddress(seed, this.config.network);
|
|
1396
|
+
} catch (e) {
|
|
1397
|
+
console.warn("Browser Spark derivation fallback failed:", e);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return addresses;
|
|
710
1401
|
}
|
|
711
1402
|
} catch (error) {
|
|
712
1403
|
console.warn("API address derivation failed:", error);
|
|
@@ -749,13 +1440,13 @@ var ZubariWdkService = class {
|
|
|
749
1440
|
/**
|
|
750
1441
|
* Get fee rates for a chain
|
|
751
1442
|
*/
|
|
752
|
-
async getFeeRates(seed,
|
|
1443
|
+
async getFeeRates(seed, chain2) {
|
|
753
1444
|
await this.initialize();
|
|
754
1445
|
try {
|
|
755
1446
|
const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/fee-rates`, {
|
|
756
1447
|
method: "POST",
|
|
757
1448
|
headers: { "Content-Type": "application/json" },
|
|
758
|
-
body: JSON.stringify({ seed, chain, network: this.config.network })
|
|
1449
|
+
body: JSON.stringify({ seed, chain: chain2, network: this.config.network })
|
|
759
1450
|
});
|
|
760
1451
|
if (response.ok) {
|
|
761
1452
|
const data = await response.json();
|
|
@@ -764,20 +1455,20 @@ var ZubariWdkService = class {
|
|
|
764
1455
|
}
|
|
765
1456
|
}
|
|
766
1457
|
} catch (error) {
|
|
767
|
-
console.warn(`Failed to fetch fee rates for ${
|
|
1458
|
+
console.warn(`Failed to fetch fee rates for ${chain2}:`, error);
|
|
768
1459
|
}
|
|
769
1460
|
return { slow: "0", normal: "0", fast: "0" };
|
|
770
1461
|
}
|
|
771
1462
|
/**
|
|
772
1463
|
* Estimate transaction fee
|
|
773
1464
|
*/
|
|
774
|
-
async estimateFee(seed,
|
|
1465
|
+
async estimateFee(seed, chain2, to, amount) {
|
|
775
1466
|
await this.initialize();
|
|
776
1467
|
try {
|
|
777
1468
|
const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/estimate-fee`, {
|
|
778
1469
|
method: "POST",
|
|
779
1470
|
headers: { "Content-Type": "application/json" },
|
|
780
|
-
body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
|
|
1471
|
+
body: JSON.stringify({ seed, chain: chain2, to, amount, network: this.config.network })
|
|
781
1472
|
});
|
|
782
1473
|
if (response.ok) {
|
|
783
1474
|
const data = await response.json();
|
|
@@ -786,52 +1477,122 @@ var ZubariWdkService = class {
|
|
|
786
1477
|
}
|
|
787
1478
|
}
|
|
788
1479
|
} catch (error) {
|
|
789
|
-
console.warn(`Failed to estimate fee for ${
|
|
1480
|
+
console.warn(`Failed to estimate fee for ${chain2}:`, error);
|
|
790
1481
|
}
|
|
791
|
-
return { fee: "0", symbol: this.getChainSymbol(
|
|
1482
|
+
return { fee: "0", symbol: this.getChainSymbol(chain2) };
|
|
792
1483
|
}
|
|
793
1484
|
/**
|
|
794
|
-
* Send a transaction
|
|
1485
|
+
* Send a transaction on any supported chain
|
|
1486
|
+
*
|
|
1487
|
+
* @param seed - BIP-39 seed phrase
|
|
1488
|
+
* @param chain - Target blockchain (ethereum, bitcoin, solana, ton, tron, spark)
|
|
1489
|
+
* @param to - Recipient address
|
|
1490
|
+
* @param amount - Amount to send (in native units: ETH, BTC, SOL, etc.)
|
|
1491
|
+
* @returns Transaction result with hash on success, or error details on failure
|
|
795
1492
|
*/
|
|
796
|
-
async sendTransaction(seed,
|
|
1493
|
+
async sendTransaction(seed, chain2, to, amount) {
|
|
797
1494
|
await this.initialize();
|
|
1495
|
+
const startTime = Date.now();
|
|
1496
|
+
console.log(`[ZubariWdkService] Sending ${chain2} transaction`, {
|
|
1497
|
+
to: `${to.slice(0, 10)}...${to.slice(-6)}`,
|
|
1498
|
+
amount,
|
|
1499
|
+
network: this.config.network
|
|
1500
|
+
});
|
|
798
1501
|
try {
|
|
799
1502
|
const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/send`, {
|
|
800
1503
|
method: "POST",
|
|
801
1504
|
headers: { "Content-Type": "application/json" },
|
|
802
|
-
body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
|
|
1505
|
+
body: JSON.stringify({ seed, chain: chain2, to, amount, network: this.config.network })
|
|
803
1506
|
});
|
|
1507
|
+
const elapsed = Date.now() - startTime;
|
|
804
1508
|
if (response.ok) {
|
|
805
1509
|
const data = await response.json();
|
|
806
1510
|
let txHash = data.txHash || data.transactionHash || data.hash;
|
|
807
1511
|
if (txHash && typeof txHash === "object" && "hash" in txHash) {
|
|
808
1512
|
txHash = txHash.hash;
|
|
809
1513
|
}
|
|
810
|
-
if (
|
|
811
|
-
|
|
1514
|
+
if (txHash) {
|
|
1515
|
+
const isValid = this.validateTxHash(chain2, txHash);
|
|
1516
|
+
if (!isValid) {
|
|
1517
|
+
console.warn(`[ZubariWdkService] Invalid ${chain2} tx hash format:`, txHash);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
console.log(`[ZubariWdkService] ${chain2} transaction ${data.success ? "SUCCESS" : "FAILED"}`, {
|
|
1521
|
+
txHash: txHash ? `${txHash.slice(0, 16)}...` : "N/A",
|
|
1522
|
+
elapsed: `${elapsed}ms`
|
|
1523
|
+
});
|
|
1524
|
+
if (!data.success) {
|
|
1525
|
+
const errorCode2 = parseChainError(chain2, data.error || "");
|
|
1526
|
+
return {
|
|
1527
|
+
success: false,
|
|
1528
|
+
error: data.error,
|
|
1529
|
+
errorCode: errorCode2,
|
|
1530
|
+
chain: chain2
|
|
1531
|
+
};
|
|
812
1532
|
}
|
|
813
1533
|
return {
|
|
814
|
-
success:
|
|
1534
|
+
success: true,
|
|
815
1535
|
txHash,
|
|
816
1536
|
from: data.from,
|
|
817
1537
|
to: data.to,
|
|
818
1538
|
amount: data.amount,
|
|
819
|
-
chain: data.chain,
|
|
820
|
-
network: data.network
|
|
1539
|
+
chain: data.chain || chain2,
|
|
1540
|
+
network: data.network || this.config.network
|
|
821
1541
|
};
|
|
822
1542
|
}
|
|
823
1543
|
const errorData = await response.json().catch(() => ({}));
|
|
1544
|
+
const errorMessage = errorData.error || `HTTP ${response.status}`;
|
|
1545
|
+
const errorCode = parseChainError(chain2, errorMessage);
|
|
1546
|
+
console.error(`[ZubariWdkService] ${chain2} transaction FAILED`, {
|
|
1547
|
+
status: response.status,
|
|
1548
|
+
error: errorMessage,
|
|
1549
|
+
errorCode,
|
|
1550
|
+
elapsed: `${elapsed}ms`
|
|
1551
|
+
});
|
|
824
1552
|
return {
|
|
825
1553
|
success: false,
|
|
826
|
-
error:
|
|
1554
|
+
error: errorMessage,
|
|
1555
|
+
errorCode,
|
|
1556
|
+
chain: chain2
|
|
827
1557
|
};
|
|
828
1558
|
} catch (error) {
|
|
1559
|
+
const elapsed = Date.now() - startTime;
|
|
1560
|
+
const errorMessage = error instanceof Error ? error.message : "Transaction failed";
|
|
1561
|
+
const errorCode = parseChainError(chain2, errorMessage);
|
|
1562
|
+
console.error(`[ZubariWdkService] ${chain2} transaction ERROR`, {
|
|
1563
|
+
error: errorMessage,
|
|
1564
|
+
errorCode,
|
|
1565
|
+
elapsed: `${elapsed}ms`
|
|
1566
|
+
});
|
|
829
1567
|
return {
|
|
830
1568
|
success: false,
|
|
831
|
-
error:
|
|
1569
|
+
error: errorMessage,
|
|
1570
|
+
errorCode,
|
|
1571
|
+
chain: chain2
|
|
832
1572
|
};
|
|
833
1573
|
}
|
|
834
1574
|
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Validate transaction hash format for a specific chain
|
|
1577
|
+
*/
|
|
1578
|
+
validateTxHash(chain2, txHash) {
|
|
1579
|
+
switch (chain2) {
|
|
1580
|
+
case "ethereum":
|
|
1581
|
+
return /^0x[a-fA-F0-9]{64}$/.test(txHash);
|
|
1582
|
+
case "bitcoin":
|
|
1583
|
+
return /^[a-fA-F0-9]{64}$/.test(txHash);
|
|
1584
|
+
case "solana":
|
|
1585
|
+
return /^[1-9A-HJ-NP-Za-km-z]{80,90}$/.test(txHash);
|
|
1586
|
+
case "ton":
|
|
1587
|
+
return txHash.length >= 40;
|
|
1588
|
+
case "tron":
|
|
1589
|
+
return /^[a-fA-F0-9]{64}$/.test(txHash);
|
|
1590
|
+
case "spark":
|
|
1591
|
+
return txHash.length >= 32;
|
|
1592
|
+
default:
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
835
1596
|
/**
|
|
836
1597
|
* Get the network configuration
|
|
837
1598
|
*/
|
|
@@ -847,7 +1608,7 @@ var ZubariWdkService = class {
|
|
|
847
1608
|
// ==========================================
|
|
848
1609
|
// Private Helper Methods
|
|
849
1610
|
// ==========================================
|
|
850
|
-
getDerivationPath(
|
|
1611
|
+
getDerivationPath(chain2) {
|
|
851
1612
|
const paths = {
|
|
852
1613
|
bitcoin: this.config.network === "testnet" ? "m/84'/1'/0'/0/0" : "m/84'/0'/0'/0/0",
|
|
853
1614
|
ethereum: "m/44'/60'/0'/0/0",
|
|
@@ -856,9 +1617,9 @@ var ZubariWdkService = class {
|
|
|
856
1617
|
solana: "m/44'/501'/0'/0'",
|
|
857
1618
|
spark: "m/44'/998'/0'/0/0"
|
|
858
1619
|
};
|
|
859
|
-
return paths[
|
|
1620
|
+
return paths[chain2];
|
|
860
1621
|
}
|
|
861
|
-
getChainSymbol(
|
|
1622
|
+
getChainSymbol(chain2) {
|
|
862
1623
|
const symbols = {
|
|
863
1624
|
ethereum: "ETH",
|
|
864
1625
|
bitcoin: "BTC",
|
|
@@ -867,16 +1628,16 @@ var ZubariWdkService = class {
|
|
|
867
1628
|
solana: "SOL",
|
|
868
1629
|
spark: "SAT"
|
|
869
1630
|
};
|
|
870
|
-
return symbols[
|
|
1631
|
+
return symbols[chain2];
|
|
871
1632
|
}
|
|
872
1633
|
/**
|
|
873
1634
|
* Derive address using browser-compatible libraries
|
|
874
1635
|
*/
|
|
875
|
-
async deriveBrowserAddress(seed,
|
|
876
|
-
const path = this.getDerivationPath(
|
|
1636
|
+
async deriveBrowserAddress(seed, chain2) {
|
|
1637
|
+
const path = this.getDerivationPath(chain2);
|
|
877
1638
|
try {
|
|
878
1639
|
let address;
|
|
879
|
-
switch (
|
|
1640
|
+
switch (chain2) {
|
|
880
1641
|
case "ethereum":
|
|
881
1642
|
address = deriveEthereumAddress(seed);
|
|
882
1643
|
break;
|
|
@@ -896,11 +1657,11 @@ var ZubariWdkService = class {
|
|
|
896
1657
|
address = await deriveTonAddress(seed);
|
|
897
1658
|
break;
|
|
898
1659
|
default:
|
|
899
|
-
throw new Error(`Unsupported chain: ${
|
|
1660
|
+
throw new Error(`Unsupported chain: ${chain2}`);
|
|
900
1661
|
}
|
|
901
|
-
return { chain, address, path };
|
|
1662
|
+
return { chain: chain2, address, path };
|
|
902
1663
|
} catch (error) {
|
|
903
|
-
console.error(`Browser derivation failed for ${
|
|
1664
|
+
console.error(`Browser derivation failed for ${chain2}:`, error);
|
|
904
1665
|
throw error;
|
|
905
1666
|
}
|
|
906
1667
|
}
|
|
@@ -966,12 +1727,12 @@ var ZubariWallet = class {
|
|
|
966
1727
|
solana: "solana",
|
|
967
1728
|
spark: "spark"
|
|
968
1729
|
};
|
|
969
|
-
const
|
|
970
|
-
if (!
|
|
1730
|
+
const chain2 = chainMap[network];
|
|
1731
|
+
if (!chain2) {
|
|
971
1732
|
throw new Error(`Unsupported network: ${network}`);
|
|
972
1733
|
}
|
|
973
1734
|
try {
|
|
974
|
-
const result = await this.wdkService.deriveAddress(this.seed,
|
|
1735
|
+
const result = await this.wdkService.deriveAddress(this.seed, chain2);
|
|
975
1736
|
const account = {
|
|
976
1737
|
network,
|
|
977
1738
|
address: result.address,
|
|
@@ -1026,13 +1787,13 @@ var ZubariWallet = class {
|
|
|
1026
1787
|
solana: "solana",
|
|
1027
1788
|
spark: "spark"
|
|
1028
1789
|
};
|
|
1029
|
-
const
|
|
1030
|
-
if (!
|
|
1790
|
+
const chain2 = chainMap[network];
|
|
1791
|
+
if (!chain2) {
|
|
1031
1792
|
throw new Error(`Unsupported network: ${network}`);
|
|
1032
1793
|
}
|
|
1033
1794
|
try {
|
|
1034
1795
|
const balances = await this.wdkService.getAllBalances(this.seed);
|
|
1035
|
-
const chainBalance = balances[
|
|
1796
|
+
const chainBalance = balances[chain2];
|
|
1036
1797
|
if (chainBalance) {
|
|
1037
1798
|
const balanceValue = BigInt(chainBalance.balance || "0");
|
|
1038
1799
|
const decimals = networkConfig.nativeCurrency.decimals;
|
|
@@ -1121,14 +1882,14 @@ var ZubariWallet = class {
|
|
|
1121
1882
|
solana: "solana",
|
|
1122
1883
|
spark: "spark"
|
|
1123
1884
|
};
|
|
1124
|
-
const
|
|
1125
|
-
if (!
|
|
1885
|
+
const chain2 = chainMap[network];
|
|
1886
|
+
if (!chain2) {
|
|
1126
1887
|
throw new Error(`Unsupported network: ${network}`);
|
|
1127
1888
|
}
|
|
1128
1889
|
try {
|
|
1129
1890
|
const result = await this.wdkService.sendTransaction(
|
|
1130
1891
|
this.seed,
|
|
1131
|
-
|
|
1892
|
+
chain2,
|
|
1132
1893
|
to,
|
|
1133
1894
|
amount.toString()
|
|
1134
1895
|
);
|
|
@@ -1803,8 +2564,8 @@ async function fetchPrices() {
|
|
|
1803
2564
|
if (response.ok) {
|
|
1804
2565
|
const data = await response.json();
|
|
1805
2566
|
const prices = {};
|
|
1806
|
-
for (const [
|
|
1807
|
-
prices[
|
|
2567
|
+
for (const [chain2, geckoId] of Object.entries(COINGECKO_IDS)) {
|
|
2568
|
+
prices[chain2] = data[geckoId]?.usd || 0;
|
|
1808
2569
|
}
|
|
1809
2570
|
priceCache = { prices, timestamp: Date.now() };
|
|
1810
2571
|
return prices;
|
|
@@ -1814,9 +2575,9 @@ async function fetchPrices() {
|
|
|
1814
2575
|
}
|
|
1815
2576
|
return priceCache?.prices || {};
|
|
1816
2577
|
}
|
|
1817
|
-
async function getPriceForChain(
|
|
2578
|
+
async function getPriceForChain(chain2) {
|
|
1818
2579
|
const prices = await fetchPrices();
|
|
1819
|
-
return prices[
|
|
2580
|
+
return prices[chain2] || 0;
|
|
1820
2581
|
}
|
|
1821
2582
|
var STORAGE_KEYS = {
|
|
1822
2583
|
ENCRYPTED_SEED: "encrypted_seed",
|
|
@@ -1836,7 +2597,7 @@ var WalletManager = class _WalletManager {
|
|
|
1836
2597
|
const isTestnet = config.network !== "mainnet";
|
|
1837
2598
|
const ethereumConfig = getNetworkConfig("ethereum", isTestnet);
|
|
1838
2599
|
this.config = {
|
|
1839
|
-
network: config.network || "
|
|
2600
|
+
network: config.network || "mainnet",
|
|
1840
2601
|
rpcUrl: config.rpcUrl || ethereumConfig.rpcUrl,
|
|
1841
2602
|
storage: config.storage || createSecureStorage(),
|
|
1842
2603
|
enabledChains: config.enabledChains || SUPPORTED_CHAINS,
|
|
@@ -2022,9 +2783,9 @@ var WalletManager = class _WalletManager {
|
|
|
2022
2783
|
if (!this.derivedAddress) {
|
|
2023
2784
|
throw new Error("Wallet not initialized");
|
|
2024
2785
|
}
|
|
2025
|
-
const
|
|
2786
|
+
const chain2 = this.config.network === "mainnet" ? chains.mainnet : chains.sepolia;
|
|
2026
2787
|
const client = viem.createPublicClient({
|
|
2027
|
-
chain,
|
|
2788
|
+
chain: chain2,
|
|
2028
2789
|
transport: viem.http(this.config.rpcUrl, {
|
|
2029
2790
|
timeout: 15e3,
|
|
2030
2791
|
// 15 second timeout
|
|
@@ -2046,9 +2807,9 @@ var WalletManager = class _WalletManager {
|
|
|
2046
2807
|
* Create viem public client for the current network
|
|
2047
2808
|
*/
|
|
2048
2809
|
getPublicClient() {
|
|
2049
|
-
const
|
|
2810
|
+
const chain2 = this.config.network === "mainnet" ? chains.mainnet : chains.sepolia;
|
|
2050
2811
|
return viem.createPublicClient({
|
|
2051
|
-
chain,
|
|
2812
|
+
chain: chain2,
|
|
2052
2813
|
transport: viem.http(this.config.rpcUrl, {
|
|
2053
2814
|
timeout: 15e3,
|
|
2054
2815
|
// 15 second timeout
|
|
@@ -2102,11 +2863,11 @@ var WalletManager = class _WalletManager {
|
|
|
2102
2863
|
*
|
|
2103
2864
|
* No fallback to placeholder addresses - WDK API is required for real addresses.
|
|
2104
2865
|
*/
|
|
2105
|
-
static async deriveAddressForChainAsync(seed,
|
|
2106
|
-
if (
|
|
2866
|
+
static async deriveAddressForChainAsync(seed, chain2, network = "mainnet", apiUrl) {
|
|
2867
|
+
if (chain2 === "ethereum") {
|
|
2107
2868
|
try {
|
|
2108
2869
|
const wdkService2 = getZubariWdkService({ network, apiUrl });
|
|
2109
|
-
const result2 = await wdkService2.deriveAddress(seed,
|
|
2870
|
+
const result2 = await wdkService2.deriveAddress(seed, chain2);
|
|
2110
2871
|
return result2.address;
|
|
2111
2872
|
} catch (error) {
|
|
2112
2873
|
console.warn("WDK service failed for Ethereum, using local derivation:", error);
|
|
@@ -2114,7 +2875,7 @@ var WalletManager = class _WalletManager {
|
|
|
2114
2875
|
}
|
|
2115
2876
|
}
|
|
2116
2877
|
const wdkService = getZubariWdkService({ network, apiUrl });
|
|
2117
|
-
const result = await wdkService.deriveAddress(seed,
|
|
2878
|
+
const result = await wdkService.deriveAddress(seed, chain2);
|
|
2118
2879
|
return result.address;
|
|
2119
2880
|
}
|
|
2120
2881
|
/**
|
|
@@ -2123,14 +2884,14 @@ var WalletManager = class _WalletManager {
|
|
|
2123
2884
|
*
|
|
2124
2885
|
* @throws Error for non-Ethereum chains - use WDK API instead
|
|
2125
2886
|
*/
|
|
2126
|
-
static deriveAddressForChain(seed,
|
|
2127
|
-
if (
|
|
2887
|
+
static deriveAddressForChain(seed, chain2) {
|
|
2888
|
+
if (chain2 === "ethereum") {
|
|
2128
2889
|
const ethPath = DERIVATION_PATHS["ethereum"];
|
|
2129
2890
|
const ethNode = ethers.HDNodeWallet.fromPhrase(seed, void 0, `${ethPath}/0`);
|
|
2130
2891
|
return ethNode.address;
|
|
2131
2892
|
}
|
|
2132
2893
|
throw new Error(
|
|
2133
|
-
`Sync derivation not supported for ${
|
|
2894
|
+
`Sync derivation not supported for ${chain2}. Use deriveAddressForChainAsync() with WDK API.`
|
|
2134
2895
|
);
|
|
2135
2896
|
}
|
|
2136
2897
|
/**
|
|
@@ -2162,9 +2923,9 @@ var WalletManager = class _WalletManager {
|
|
|
2162
2923
|
const wdkAddresses = await this.wdkService.deriveAllAddresses(this.currentSeed);
|
|
2163
2924
|
const enabledChainsSet = new Set(this.config.enabledChains);
|
|
2164
2925
|
const addresses = {};
|
|
2165
|
-
for (const [
|
|
2166
|
-
if (enabledChainsSet.has(
|
|
2167
|
-
addresses[
|
|
2926
|
+
for (const [chain2, address] of Object.entries(wdkAddresses)) {
|
|
2927
|
+
if (enabledChainsSet.has(chain2) && address) {
|
|
2928
|
+
addresses[chain2] = address;
|
|
2168
2929
|
}
|
|
2169
2930
|
}
|
|
2170
2931
|
this.derivedAddresses = addresses;
|
|
@@ -2205,10 +2966,10 @@ var WalletManager = class _WalletManager {
|
|
|
2205
2966
|
*/
|
|
2206
2967
|
normalizeAddresses(addresses) {
|
|
2207
2968
|
const normalized = {};
|
|
2208
|
-
for (const [
|
|
2969
|
+
for (const [chain2, value] of Object.entries(addresses)) {
|
|
2209
2970
|
const addr = this.normalizeAddress(value);
|
|
2210
2971
|
if (addr) {
|
|
2211
|
-
normalized[
|
|
2972
|
+
normalized[chain2] = addr;
|
|
2212
2973
|
}
|
|
2213
2974
|
}
|
|
2214
2975
|
return normalized;
|
|
@@ -2261,20 +3022,20 @@ var WalletManager = class _WalletManager {
|
|
|
2261
3022
|
* Get address for a specific chain
|
|
2262
3023
|
* Returns cached address or null - use deriveAllAddressesAsync to derive addresses
|
|
2263
3024
|
*/
|
|
2264
|
-
getAddressForChain(
|
|
2265
|
-
const cachedValue = this.derivedAddresses[
|
|
3025
|
+
getAddressForChain(chain2) {
|
|
3026
|
+
const cachedValue = this.derivedAddresses[chain2];
|
|
2266
3027
|
if (cachedValue) {
|
|
2267
|
-
console.log(`[WalletManager] getAddressForChain(${
|
|
3028
|
+
console.log(`[WalletManager] getAddressForChain(${chain2}) cached value:`, cachedValue, "type:", typeof cachedValue);
|
|
2268
3029
|
const addr = this.normalizeAddress(cachedValue);
|
|
2269
|
-
console.log(`[WalletManager] getAddressForChain(${
|
|
3030
|
+
console.log(`[WalletManager] getAddressForChain(${chain2}) normalized:`, addr);
|
|
2270
3031
|
if (addr) {
|
|
2271
|
-
this.derivedAddresses[
|
|
3032
|
+
this.derivedAddresses[chain2] = addr;
|
|
2272
3033
|
return addr;
|
|
2273
3034
|
}
|
|
2274
3035
|
}
|
|
2275
|
-
if (
|
|
2276
|
-
this.derivedAddresses[
|
|
2277
|
-
return this.derivedAddresses[
|
|
3036
|
+
if (chain2 === "ethereum" && this.currentSeed) {
|
|
3037
|
+
this.derivedAddresses[chain2] = _WalletManager.deriveAddressForChain(this.currentSeed, chain2);
|
|
3038
|
+
return this.derivedAddresses[chain2];
|
|
2278
3039
|
}
|
|
2279
3040
|
return null;
|
|
2280
3041
|
}
|
|
@@ -2287,11 +3048,11 @@ var WalletManager = class _WalletManager {
|
|
|
2287
3048
|
/**
|
|
2288
3049
|
* Set the selected chain
|
|
2289
3050
|
*/
|
|
2290
|
-
setSelectedChain(
|
|
2291
|
-
if (!this.config.enabledChains.includes(
|
|
2292
|
-
throw new Error(`Chain ${
|
|
3051
|
+
setSelectedChain(chain2) {
|
|
3052
|
+
if (!this.config.enabledChains.includes(chain2)) {
|
|
3053
|
+
throw new Error(`Chain ${chain2} is not enabled`);
|
|
2293
3054
|
}
|
|
2294
|
-
this.selectedChain =
|
|
3055
|
+
this.selectedChain = chain2;
|
|
2295
3056
|
}
|
|
2296
3057
|
/**
|
|
2297
3058
|
* Get the currently selected chain
|
|
@@ -2308,42 +3069,69 @@ var WalletManager = class _WalletManager {
|
|
|
2308
3069
|
/**
|
|
2309
3070
|
* Get chain configuration
|
|
2310
3071
|
*/
|
|
2311
|
-
getChainConfig(
|
|
2312
|
-
return getNetworkConfig(
|
|
3072
|
+
getChainConfig(chain2) {
|
|
3073
|
+
return getNetworkConfig(chain2, this.config.network === "testnet");
|
|
2313
3074
|
}
|
|
2314
3075
|
/**
|
|
2315
3076
|
* Fetch balance for a specific chain
|
|
2316
3077
|
* Note: Currently only Ethereum is implemented
|
|
2317
3078
|
*/
|
|
2318
|
-
async fetchBalanceForChain(
|
|
2319
|
-
const address = this.getAddressForChain(
|
|
3079
|
+
async fetchBalanceForChain(chain2) {
|
|
3080
|
+
const address = this.getAddressForChain(chain2);
|
|
2320
3081
|
if (!address) {
|
|
2321
|
-
throw new Error(`No address for chain ${
|
|
3082
|
+
throw new Error(`No address for chain ${chain2}`);
|
|
2322
3083
|
}
|
|
2323
|
-
const networkConfig = this.getChainConfig(
|
|
3084
|
+
const networkConfig = this.getChainConfig(chain2);
|
|
2324
3085
|
let balance = "0";
|
|
2325
|
-
|
|
3086
|
+
const tokenBalances = {};
|
|
3087
|
+
if (chain2 === "ethereum") {
|
|
2326
3088
|
const viemChain = this.config.network === "mainnet" ? chains.mainnet : chains.sepolia;
|
|
2327
|
-
|
|
3089
|
+
const isTestnet = this.config.network !== "mainnet";
|
|
2328
3090
|
const client = viem.createPublicClient({
|
|
2329
3091
|
chain: viemChain,
|
|
2330
3092
|
transport: viem.http(this.config.rpcUrl, {
|
|
2331
3093
|
timeout: 15e3,
|
|
2332
|
-
// 15 second timeout
|
|
2333
3094
|
retryCount: 2,
|
|
2334
3095
|
retryDelay: 1e3
|
|
2335
3096
|
})
|
|
2336
3097
|
});
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
3098
|
+
const usdtAddr = USDT_ADDRESSES.ethereum?.[isTestnet ? "testnet" : "mainnet"];
|
|
3099
|
+
const erc20BalanceOfAbi = [{
|
|
3100
|
+
type: "function",
|
|
3101
|
+
name: "balanceOf",
|
|
3102
|
+
stateMutability: "view",
|
|
3103
|
+
inputs: [{ name: "account", type: "address" }],
|
|
3104
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
3105
|
+
}];
|
|
3106
|
+
const checksumAddr = viem.getAddress(address);
|
|
3107
|
+
const [ethResult, usdtResult] = await Promise.allSettled([
|
|
3108
|
+
client.getBalance({ address: checksumAddr }),
|
|
3109
|
+
usdtAddr ? client.readContract({
|
|
3110
|
+
address: viem.getAddress(usdtAddr),
|
|
3111
|
+
abi: erc20BalanceOfAbi,
|
|
3112
|
+
functionName: "balanceOf",
|
|
3113
|
+
args: [checksumAddr]
|
|
3114
|
+
}) : Promise.resolve(null)
|
|
3115
|
+
]);
|
|
3116
|
+
if (ethResult.status === "fulfilled") {
|
|
3117
|
+
balance = viem.formatEther(ethResult.value);
|
|
3118
|
+
} else {
|
|
3119
|
+
console.error(`[WalletManager] Failed to fetch ETH balance:`, ethResult.reason);
|
|
2345
3120
|
}
|
|
2346
|
-
|
|
3121
|
+
if (usdtResult.status === "fulfilled" && usdtResult.value != null) {
|
|
3122
|
+
try {
|
|
3123
|
+
const rawUsdt = BigInt(usdtResult.value);
|
|
3124
|
+
const usdtAmount = Number(rawUsdt) / 1e6;
|
|
3125
|
+
if (usdtAmount > 0) {
|
|
3126
|
+
tokenBalances.USDT = { balance: usdtAmount.toFixed(6), balanceUsd: usdtAmount };
|
|
3127
|
+
}
|
|
3128
|
+
} catch (err) {
|
|
3129
|
+
console.warn("[WalletManager] Failed to parse ETH USDT balance:", err);
|
|
3130
|
+
}
|
|
3131
|
+
} else if (usdtResult.status === "rejected") {
|
|
3132
|
+
console.warn("[WalletManager] Failed to fetch ETH USDT balance:", usdtResult.reason);
|
|
3133
|
+
}
|
|
3134
|
+
} else if (chain2 === "bitcoin") {
|
|
2347
3135
|
const isMainnet = this.config.network === "mainnet" || address.startsWith("bc1") || address.startsWith("1") || address.startsWith("3");
|
|
2348
3136
|
const apisToTry = isMainnet ? ["https://mempool.space/api"] : [
|
|
2349
3137
|
"https://mempool.space/testnet/api",
|
|
@@ -2375,7 +3163,7 @@ var WalletManager = class _WalletManager {
|
|
|
2375
3163
|
console.warn(`Failed to fetch from ${apiUrl}:`, error);
|
|
2376
3164
|
}
|
|
2377
3165
|
}
|
|
2378
|
-
} else if (
|
|
3166
|
+
} else if (chain2 === "solana") {
|
|
2379
3167
|
const rpcUrl = this.config.network === "mainnet" ? "https://api.mainnet-beta.solana.com" : "https://api.devnet.solana.com";
|
|
2380
3168
|
try {
|
|
2381
3169
|
const response = await fetch(rpcUrl, {
|
|
@@ -2395,10 +3183,43 @@ var WalletManager = class _WalletManager {
|
|
|
2395
3183
|
}
|
|
2396
3184
|
}
|
|
2397
3185
|
} catch (error) {
|
|
2398
|
-
console.warn(`Failed to fetch ${
|
|
3186
|
+
console.warn(`Failed to fetch ${chain2} balance:`, error);
|
|
3187
|
+
}
|
|
3188
|
+
const isTestnet = this.config.network !== "mainnet";
|
|
3189
|
+
const usdtMint = USDT_ADDRESSES.solana?.[isTestnet ? "testnet" : "mainnet"];
|
|
3190
|
+
if (usdtMint) {
|
|
3191
|
+
try {
|
|
3192
|
+
const tokenResponse = await fetch(rpcUrl, {
|
|
3193
|
+
method: "POST",
|
|
3194
|
+
headers: { "Content-Type": "application/json" },
|
|
3195
|
+
body: JSON.stringify({
|
|
3196
|
+
jsonrpc: "2.0",
|
|
3197
|
+
id: 2,
|
|
3198
|
+
method: "getTokenAccountsByOwner",
|
|
3199
|
+
params: [
|
|
3200
|
+
address,
|
|
3201
|
+
{ mint: usdtMint },
|
|
3202
|
+
{ encoding: "jsonParsed" }
|
|
3203
|
+
]
|
|
3204
|
+
})
|
|
3205
|
+
});
|
|
3206
|
+
if (tokenResponse.ok) {
|
|
3207
|
+
const tokenData = await tokenResponse.json();
|
|
3208
|
+
const accounts = tokenData.result?.value;
|
|
3209
|
+
if (accounts && accounts.length > 0) {
|
|
3210
|
+
const uiAmount = accounts[0].account?.data?.parsed?.info?.tokenAmount?.uiAmount;
|
|
3211
|
+
if (uiAmount && uiAmount > 0) {
|
|
3212
|
+
tokenBalances.USDT = { balance: uiAmount.toFixed(6), balanceUsd: uiAmount };
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
} catch (error) {
|
|
3217
|
+
console.warn("Failed to fetch Solana USDT balance:", error);
|
|
3218
|
+
}
|
|
2399
3219
|
}
|
|
2400
|
-
} else if (
|
|
2401
|
-
const
|
|
3220
|
+
} else if (chain2 === "tron") {
|
|
3221
|
+
const tronConfig = getNetworkConfig("tron", this.config.network !== "mainnet");
|
|
3222
|
+
const baseUrl = tronConfig.rpcUrl;
|
|
2402
3223
|
try {
|
|
2403
3224
|
const response = await fetch(`${baseUrl}/v1/accounts/${address}`, {
|
|
2404
3225
|
headers: { "Accept": "application/json" }
|
|
@@ -2408,12 +3229,28 @@ var WalletManager = class _WalletManager {
|
|
|
2408
3229
|
if (data.data?.[0]?.balance !== void 0) {
|
|
2409
3230
|
balance = (data.data[0].balance / 1e6).toFixed(6);
|
|
2410
3231
|
}
|
|
3232
|
+
const isTestnet = this.config.network !== "mainnet";
|
|
3233
|
+
const usdtAddr = USDT_ADDRESSES.tron?.[isTestnet ? "testnet" : "mainnet"];
|
|
3234
|
+
if (usdtAddr && data.data?.[0]?.trc20) {
|
|
3235
|
+
const trc20List = data.data[0].trc20;
|
|
3236
|
+
for (const tokenObj of trc20List) {
|
|
3237
|
+
if (tokenObj[usdtAddr]) {
|
|
3238
|
+
const rawUsdtBalance = BigInt(tokenObj[usdtAddr]);
|
|
3239
|
+
const usdtAmount = Number(rawUsdtBalance) / 1e6;
|
|
3240
|
+
if (usdtAmount > 0) {
|
|
3241
|
+
tokenBalances.USDT = { balance: usdtAmount.toFixed(6), balanceUsd: usdtAmount };
|
|
3242
|
+
}
|
|
3243
|
+
break;
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
2411
3247
|
}
|
|
2412
3248
|
} catch (error) {
|
|
2413
|
-
console.warn(`Failed to fetch ${
|
|
3249
|
+
console.warn(`Failed to fetch ${chain2} balance:`, error);
|
|
2414
3250
|
}
|
|
2415
|
-
} else if (
|
|
2416
|
-
const
|
|
3251
|
+
} else if (chain2 === "ton") {
|
|
3252
|
+
const isTestnet = this.config.network !== "mainnet";
|
|
3253
|
+
const baseUrl = isTestnet ? "https://testnet.toncenter.com/api/v2" : "https://toncenter.com/api/v2";
|
|
2417
3254
|
try {
|
|
2418
3255
|
const response = await fetch(`${baseUrl}/getAddressBalance?address=${address}`, {
|
|
2419
3256
|
headers: { "Accept": "application/json" }
|
|
@@ -2427,9 +3264,34 @@ var WalletManager = class _WalletManager {
|
|
|
2427
3264
|
}
|
|
2428
3265
|
}
|
|
2429
3266
|
} catch (error) {
|
|
2430
|
-
console.warn(`Failed to fetch ${
|
|
3267
|
+
console.warn(`Failed to fetch ${chain2} balance:`, error);
|
|
3268
|
+
}
|
|
3269
|
+
const usdtJetton = USDT_ADDRESSES.ton?.[isTestnet ? "testnet" : "mainnet"];
|
|
3270
|
+
if (usdtJetton) {
|
|
3271
|
+
const v3BaseUrl = isTestnet ? "https://testnet.toncenter.com/api/v3" : "https://toncenter.com/api/v3";
|
|
3272
|
+
try {
|
|
3273
|
+
const jettonResponse = await fetch(
|
|
3274
|
+
`${v3BaseUrl}/jetton/wallets?owner_address=${address}&jetton_address=${usdtJetton}&limit=1`,
|
|
3275
|
+
{ headers: { "Accept": "application/json" } }
|
|
3276
|
+
);
|
|
3277
|
+
if (jettonResponse.ok) {
|
|
3278
|
+
const jettonData = await jettonResponse.json();
|
|
3279
|
+
const wallets = jettonData.jetton_wallets;
|
|
3280
|
+
if (wallets && wallets.length > 0) {
|
|
3281
|
+
const rawBalance = wallets[0].balance;
|
|
3282
|
+
if (rawBalance) {
|
|
3283
|
+
const usdtAmount = Number(BigInt(rawBalance)) / 1e6;
|
|
3284
|
+
if (usdtAmount > 0) {
|
|
3285
|
+
tokenBalances.USDT = { balance: usdtAmount.toFixed(6), balanceUsd: usdtAmount };
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
} catch (error) {
|
|
3291
|
+
console.warn("Failed to fetch TON USDT jetton balance:", error);
|
|
3292
|
+
}
|
|
2431
3293
|
}
|
|
2432
|
-
} else if (
|
|
3294
|
+
} else if (chain2 === "spark") {
|
|
2433
3295
|
try {
|
|
2434
3296
|
const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/balance`, {
|
|
2435
3297
|
method: "POST",
|
|
@@ -2448,19 +3310,20 @@ var WalletManager = class _WalletManager {
|
|
|
2448
3310
|
}
|
|
2449
3311
|
}
|
|
2450
3312
|
} catch (error) {
|
|
2451
|
-
console.warn(`Failed to fetch ${
|
|
3313
|
+
console.warn(`Failed to fetch ${chain2} balance:`, error);
|
|
2452
3314
|
}
|
|
2453
3315
|
}
|
|
2454
|
-
const priceUsd = await getPriceForChain(
|
|
3316
|
+
const priceUsd = await getPriceForChain(chain2);
|
|
2455
3317
|
const balanceNum = parseFloat(balance) || 0;
|
|
2456
3318
|
const balanceUsd = balanceNum * priceUsd;
|
|
2457
3319
|
return {
|
|
2458
|
-
chain,
|
|
3320
|
+
chain: chain2,
|
|
2459
3321
|
symbol: networkConfig.nativeCurrency.symbol,
|
|
2460
3322
|
balance,
|
|
2461
3323
|
balanceUsd,
|
|
2462
3324
|
address,
|
|
2463
|
-
decimals: networkConfig.nativeCurrency.decimals
|
|
3325
|
+
decimals: networkConfig.nativeCurrency.decimals,
|
|
3326
|
+
...Object.keys(tokenBalances).length > 0 ? { tokenBalances } : {}
|
|
2464
3327
|
};
|
|
2465
3328
|
}
|
|
2466
3329
|
/**
|
|
@@ -2468,19 +3331,19 @@ var WalletManager = class _WalletManager {
|
|
|
2468
3331
|
*/
|
|
2469
3332
|
async fetchAllBalances() {
|
|
2470
3333
|
const balances = [];
|
|
2471
|
-
for (const
|
|
3334
|
+
for (const chain2 of this.config.enabledChains) {
|
|
2472
3335
|
try {
|
|
2473
|
-
const balance = await this.fetchBalanceForChain(
|
|
3336
|
+
const balance = await this.fetchBalanceForChain(chain2);
|
|
2474
3337
|
balances.push(balance);
|
|
2475
3338
|
} catch (error) {
|
|
2476
|
-
console.error(`Failed to fetch balance for ${
|
|
2477
|
-
const networkConfig = this.getChainConfig(
|
|
3339
|
+
console.error(`Failed to fetch balance for ${chain2}:`, error);
|
|
3340
|
+
const networkConfig = this.getChainConfig(chain2);
|
|
2478
3341
|
balances.push({
|
|
2479
|
-
chain,
|
|
3342
|
+
chain: chain2,
|
|
2480
3343
|
symbol: networkConfig.nativeCurrency.symbol,
|
|
2481
3344
|
balance: "0",
|
|
2482
3345
|
balanceUsd: 0,
|
|
2483
|
-
address: this.getAddressForChain(
|
|
3346
|
+
address: this.getAddressForChain(chain2) || "",
|
|
2484
3347
|
decimals: networkConfig.nativeCurrency.decimals
|
|
2485
3348
|
});
|
|
2486
3349
|
}
|
|
@@ -2510,13 +3373,13 @@ var WalletManager = class _WalletManager {
|
|
|
2510
3373
|
* @param token - Optional token symbol (e.g., 'USDT' for stablecoins)
|
|
2511
3374
|
* @returns Transaction result with hash and status
|
|
2512
3375
|
*/
|
|
2513
|
-
async sendTransaction(
|
|
3376
|
+
async sendTransaction(chain2, to, amount, token) {
|
|
2514
3377
|
if (!this.currentSeed) {
|
|
2515
3378
|
return { success: false, error: "Wallet is locked" };
|
|
2516
3379
|
}
|
|
2517
|
-
const fromAddress = this.getAddressForChain(
|
|
3380
|
+
const fromAddress = this.getAddressForChain(chain2);
|
|
2518
3381
|
if (!fromAddress) {
|
|
2519
|
-
return { success: false, error: `No address for chain ${
|
|
3382
|
+
return { success: false, error: `No address for chain ${chain2}` };
|
|
2520
3383
|
}
|
|
2521
3384
|
try {
|
|
2522
3385
|
const headers = {
|
|
@@ -2530,7 +3393,7 @@ var WalletManager = class _WalletManager {
|
|
|
2530
3393
|
headers,
|
|
2531
3394
|
body: JSON.stringify({
|
|
2532
3395
|
seed: this.currentSeed,
|
|
2533
|
-
chain,
|
|
3396
|
+
chain: chain2,
|
|
2534
3397
|
to,
|
|
2535
3398
|
amount,
|
|
2536
3399
|
token,
|
|
@@ -2539,12 +3402,12 @@ var WalletManager = class _WalletManager {
|
|
|
2539
3402
|
});
|
|
2540
3403
|
if (response.ok) {
|
|
2541
3404
|
const data = await response.json();
|
|
2542
|
-
console.log(`Transaction sent on ${
|
|
3405
|
+
console.log(`Transaction sent on ${chain2}:`, data);
|
|
2543
3406
|
let txHash = data.txHash || data.transactionHash || data.hash;
|
|
2544
3407
|
if (txHash && typeof txHash === "object" && "hash" in txHash) {
|
|
2545
3408
|
txHash = txHash.hash;
|
|
2546
3409
|
}
|
|
2547
|
-
if (
|
|
3410
|
+
if (chain2 === "ethereum" && txHash && (typeof txHash !== "string" || !txHash.startsWith("0x") || txHash.length !== 66)) {
|
|
2548
3411
|
console.warn(`Invalid Ethereum tx hash format: ${txHash} (length: ${txHash?.length}, expected: 66)`);
|
|
2549
3412
|
}
|
|
2550
3413
|
return {
|
|
@@ -2553,7 +3416,7 @@ var WalletManager = class _WalletManager {
|
|
|
2553
3416
|
from: fromAddress,
|
|
2554
3417
|
to,
|
|
2555
3418
|
amount,
|
|
2556
|
-
chain
|
|
3419
|
+
chain: chain2
|
|
2557
3420
|
};
|
|
2558
3421
|
}
|
|
2559
3422
|
const errorData = await response.json().catch(() => ({}));
|
|
@@ -2562,7 +3425,7 @@ var WalletManager = class _WalletManager {
|
|
|
2562
3425
|
error: errorData.error || `HTTP ${response.status}`
|
|
2563
3426
|
};
|
|
2564
3427
|
} catch (error) {
|
|
2565
|
-
console.error(`Transaction failed on ${
|
|
3428
|
+
console.error(`Transaction failed on ${chain2}:`, error);
|
|
2566
3429
|
return {
|
|
2567
3430
|
success: false,
|
|
2568
3431
|
error: error instanceof Error ? error.message : "Transaction failed"
|
|
@@ -2572,7 +3435,7 @@ var WalletManager = class _WalletManager {
|
|
|
2572
3435
|
/**
|
|
2573
3436
|
* Estimate transaction fee using Tether WDK
|
|
2574
3437
|
*/
|
|
2575
|
-
async estimateFee(
|
|
3438
|
+
async estimateFee(chain2, to, amount, token) {
|
|
2576
3439
|
try {
|
|
2577
3440
|
const headers = {
|
|
2578
3441
|
"Content-Type": "application/json"
|
|
@@ -2584,7 +3447,7 @@ var WalletManager = class _WalletManager {
|
|
|
2584
3447
|
method: "POST",
|
|
2585
3448
|
headers,
|
|
2586
3449
|
body: JSON.stringify({
|
|
2587
|
-
chain,
|
|
3450
|
+
chain: chain2,
|
|
2588
3451
|
to,
|
|
2589
3452
|
amount,
|
|
2590
3453
|
token,
|
|
@@ -2608,6 +3471,14 @@ var WalletManager = class _WalletManager {
|
|
|
2608
3471
|
}
|
|
2609
3472
|
}
|
|
2610
3473
|
};
|
|
3474
|
+
/*! Bundled license information:
|
|
3475
|
+
|
|
3476
|
+
@scure/base/index.js:
|
|
3477
|
+
(*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
3478
|
+
|
|
3479
|
+
@scure/bip32/index.js:
|
|
3480
|
+
(*! scure-bip32 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
|
|
3481
|
+
*/
|
|
2611
3482
|
|
|
2612
3483
|
exports.SUPPORTED_CHAINS = SUPPORTED_CHAINS;
|
|
2613
3484
|
exports.WalletManager = WalletManager;
|