@zubari/sdk 0.2.8 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/{TransactionService-8xSEGoWA.d.mts → TransactionService-DURp3bRL.d.ts} +34 -10
  2. package/dist/{TransactionService-CaIcCoqY.d.ts → TransactionService-DuMJmrG3.d.mts} +34 -10
  3. package/dist/{WalletManager-CCs4Jsv7.d.ts → WalletManager-CEjN-YBF.d.ts} +12 -12
  4. package/dist/{WalletManager-B1qvFF4K.d.mts → WalletManager-bo35aHOJ.d.mts} +12 -12
  5. package/dist/{index-BOc9U2TK.d.mts → index-BpjMiC3n.d.ts} +22 -11
  6. package/dist/{index-Cx389p_j.d.mts → index-DF0Gf8NK.d.mts} +7 -1
  7. package/dist/{index-Cx389p_j.d.ts → index-DF0Gf8NK.d.ts} +7 -1
  8. package/dist/{index-Cqrpp3XA.d.ts → index-DJnsirV5.d.mts} +22 -11
  9. package/dist/index.d.mts +4 -4
  10. package/dist/index.d.ts +4 -4
  11. package/dist/index.js +3064 -1770
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +3064 -1770
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/protocols/index.d.mts +54 -22
  16. package/dist/protocols/index.d.ts +54 -22
  17. package/dist/protocols/index.js +1008 -76
  18. package/dist/protocols/index.js.map +1 -1
  19. package/dist/protocols/index.mjs +1008 -76
  20. package/dist/protocols/index.mjs.map +1 -1
  21. package/dist/react/index.d.mts +3 -3
  22. package/dist/react/index.d.ts +3 -3
  23. package/dist/react/index.js +884 -884
  24. package/dist/react/index.js.map +1 -1
  25. package/dist/react/index.mjs +884 -884
  26. package/dist/react/index.mjs.map +1 -1
  27. package/dist/services/index.d.mts +2 -2
  28. package/dist/services/index.d.ts +2 -2
  29. package/dist/services/index.js +152 -75
  30. package/dist/services/index.js.map +1 -1
  31. package/dist/services/index.mjs +152 -75
  32. package/dist/services/index.mjs.map +1 -1
  33. package/dist/wallet/index.d.mts +3 -3
  34. package/dist/wallet/index.d.ts +3 -3
  35. package/dist/wallet/index.js +1352 -1105
  36. package/dist/wallet/index.js.map +1 -1
  37. package/dist/wallet/index.mjs +1352 -1105
  38. package/dist/wallet/index.mjs.map +1 -1
  39. package/package.json +13 -12
@@ -1,13 +1,13 @@
1
1
  import { useMemo, useState, useCallback, useEffect } from 'react';
2
2
  import { Wallet, HDNodeWallet } from 'ethers';
3
- import { createPublicClient, http, formatEther } from 'viem';
4
- import { mainnet, sepolia } from 'viem/chains';
5
3
  import { generateMnemonic, validateMnemonic, mnemonicToSeedSync } from '@scure/bip39';
6
4
  import { wordlist } from '@scure/bip39/wordlists/english';
7
5
  import { HDKey } from '@scure/bip32';
8
6
  import { bech32, base58check } from '@scure/base';
9
7
  import { sha256 } from '@noble/hashes/sha256';
10
8
  import { ripemd160 } from '@noble/hashes/ripemd160';
9
+ import { createPublicClient, http, formatEther } from 'viem';
10
+ import { mainnet, sepolia } from 'viem/chains';
11
11
 
12
12
  // src/react/useWalletManager.ts
13
13
 
@@ -131,1038 +131,1038 @@ function getNetworkConfig(network, isTestnet = false) {
131
131
  };
132
132
  }
133
133
 
134
- // src/security/KeyManager.ts
135
- var KeyManager = class {
136
- static ALGORITHM = "AES-GCM";
137
- static KEY_LENGTH = 256;
138
- static IV_LENGTH = 12;
139
- static SALT_LENGTH = 16;
140
- static PBKDF2_ITERATIONS = 1e5;
141
- /**
142
- * Encrypt a seed phrase with a password
143
- */
144
- static async encryptSeed(seed, password) {
145
- const encoder = new TextEncoder();
146
- const seedData = encoder.encode(seed);
147
- const salt = crypto.getRandomValues(new Uint8Array(this.SALT_LENGTH));
148
- const iv = crypto.getRandomValues(new Uint8Array(this.IV_LENGTH));
149
- const key = await this.deriveKey(password, salt);
150
- const encrypted = await crypto.subtle.encrypt(
151
- { name: this.ALGORITHM, iv },
152
- key,
153
- seedData
154
- );
155
- const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength);
156
- combined.set(salt, 0);
157
- combined.set(iv, salt.length);
158
- combined.set(new Uint8Array(encrypted), salt.length + iv.length);
159
- return btoa(String.fromCharCode(...combined));
134
+ // src/services/WdkApiClient.ts
135
+ var WdkApiClient = class {
136
+ config;
137
+ constructor(config) {
138
+ this.config = {
139
+ baseUrl: config.baseUrl,
140
+ timeout: config.timeout || 3e4
141
+ };
160
142
  }
161
143
  /**
162
- * Decrypt a seed phrase with a password
144
+ * Generate a new BIP-39 seed phrase using Tether WDK
163
145
  */
164
- static async decryptSeed(encryptedData, password) {
165
- const combined = new Uint8Array(
166
- atob(encryptedData).split("").map((c) => c.charCodeAt(0))
167
- );
168
- const salt = combined.slice(0, this.SALT_LENGTH);
169
- const iv = combined.slice(this.SALT_LENGTH, this.SALT_LENGTH + this.IV_LENGTH);
170
- const encrypted = combined.slice(this.SALT_LENGTH + this.IV_LENGTH);
171
- const key = await this.deriveKey(password, salt);
172
- const decrypted = await crypto.subtle.decrypt(
173
- { name: this.ALGORITHM, iv },
174
- key,
175
- encrypted
176
- );
177
- const decoder = new TextDecoder();
178
- return decoder.decode(decrypted);
146
+ async generateSeed() {
147
+ try {
148
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/generate-seed`, {
149
+ method: "POST",
150
+ headers: {
151
+ "Content-Type": "application/json"
152
+ }
153
+ });
154
+ return await response.json();
155
+ } catch (error) {
156
+ return {
157
+ success: false,
158
+ error: error instanceof Error ? error.message : "Failed to generate seed"
159
+ };
160
+ }
179
161
  }
180
162
  /**
181
- * Derive encryption key from password using PBKDF2
163
+ * Validate a BIP-39 seed phrase
182
164
  */
183
- static async deriveKey(password, salt) {
184
- const encoder = new TextEncoder();
185
- const passwordData = encoder.encode(password);
186
- const keyMaterial = await crypto.subtle.importKey(
187
- "raw",
188
- passwordData,
189
- "PBKDF2",
190
- false,
191
- ["deriveKey"]
192
- );
193
- return crypto.subtle.deriveKey(
194
- {
195
- name: "PBKDF2",
196
- salt: salt.buffer.slice(salt.byteOffset, salt.byteOffset + salt.byteLength),
197
- iterations: this.PBKDF2_ITERATIONS,
198
- hash: "SHA-256"
199
- },
200
- keyMaterial,
201
- { name: this.ALGORITHM, length: this.KEY_LENGTH },
202
- false,
203
- ["encrypt", "decrypt"]
204
- );
165
+ async validateSeed(seed) {
166
+ try {
167
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/validate-seed`, {
168
+ method: "POST",
169
+ headers: {
170
+ "Content-Type": "application/json"
171
+ },
172
+ body: JSON.stringify({ seed })
173
+ });
174
+ return await response.json();
175
+ } catch (error) {
176
+ return {
177
+ success: false,
178
+ error: error instanceof Error ? error.message : "Failed to validate seed"
179
+ };
180
+ }
205
181
  }
206
182
  /**
207
- * Validate a BIP-39 seed phrase (basic validation)
183
+ * Derive address for a specific chain using Tether WDK
208
184
  */
209
- static validateSeedPhrase(seed) {
210
- const words = seed.trim().split(/\s+/);
211
- const validWordCounts = [12, 15, 18, 21, 24];
212
- return validWordCounts.includes(words.length);
185
+ async deriveAddress(seed, chain, network = "testnet") {
186
+ try {
187
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/derive-address`, {
188
+ method: "POST",
189
+ headers: {
190
+ "Content-Type": "application/json"
191
+ },
192
+ body: JSON.stringify({ seed, chain, network })
193
+ });
194
+ return await response.json();
195
+ } catch (error) {
196
+ return {
197
+ success: false,
198
+ error: error instanceof Error ? error.message : "Failed to derive address"
199
+ };
200
+ }
213
201
  }
214
202
  /**
215
- * Generate a random encryption key (for backup purposes)
203
+ * Derive addresses for all chains using Tether WDK
216
204
  */
217
- static generateBackupKey() {
218
- const bytes = crypto.getRandomValues(new Uint8Array(32));
219
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
220
- }
221
- };
222
-
223
- // src/storage/SecureStorage.ts
224
- var KeychainStorageAdapter = class {
225
- serviceName;
226
- constructor(serviceName = "com.zubari.wallet") {
227
- this.serviceName = serviceName;
228
- }
229
- async setItem(key, value) {
230
- if (typeof global !== "undefined" && global.KeychainModule) {
231
- await global.KeychainModule.setItem(this.serviceName, key, value);
232
- } else {
233
- throw new Error("Keychain not available on this platform");
205
+ async deriveAllAddresses(seed, network = "testnet") {
206
+ try {
207
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/derive-all`, {
208
+ method: "POST",
209
+ headers: {
210
+ "Content-Type": "application/json"
211
+ },
212
+ body: JSON.stringify({ seed, network })
213
+ });
214
+ return await response.json();
215
+ } catch (error) {
216
+ return {
217
+ success: false,
218
+ error: error instanceof Error ? error.message : "Failed to derive addresses"
219
+ };
234
220
  }
235
221
  }
236
- async getItem(key) {
237
- if (typeof global !== "undefined" && global.KeychainModule) {
238
- return global.KeychainModule.getItem(this.serviceName, key);
222
+ /**
223
+ * Send a transaction on a specific chain using Tether WDK
224
+ */
225
+ async sendTransaction(seed, chain, to, amount, network = "testnet") {
226
+ try {
227
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/send`, {
228
+ method: "POST",
229
+ headers: {
230
+ "Content-Type": "application/json"
231
+ },
232
+ body: JSON.stringify({ seed, chain, to, amount, network })
233
+ });
234
+ return await response.json();
235
+ } catch (error) {
236
+ return {
237
+ success: false,
238
+ error: error instanceof Error ? error.message : "Failed to send transaction"
239
+ };
239
240
  }
240
- throw new Error("Keychain not available on this platform");
241
241
  }
242
- async removeItem(key) {
243
- if (typeof global !== "undefined" && global.KeychainModule) {
244
- await global.KeychainModule.removeItem(this.serviceName, key);
245
- } else {
246
- throw new Error("Keychain not available on this platform");
242
+ /**
243
+ * Get transaction history for an address on a specific chain
244
+ * Fetches from blockchain explorers (Etherscan, mempool.space, etc.)
245
+ */
246
+ async getTransactionHistory(seed, chain, network = "testnet", limit = 10) {
247
+ try {
248
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/history`, {
249
+ method: "POST",
250
+ headers: {
251
+ "Content-Type": "application/json"
252
+ },
253
+ body: JSON.stringify({ seed, chain, network, limit })
254
+ });
255
+ return await response.json();
256
+ } catch (error) {
257
+ return {
258
+ success: false,
259
+ error: error instanceof Error ? error.message : "Failed to get transaction history"
260
+ };
247
261
  }
248
262
  }
249
- async hasItem(key) {
250
- const value = await this.getItem(key);
251
- return value !== null;
252
- }
253
- async clear() {
254
- if (typeof global !== "undefined" && global.KeychainModule) {
255
- await global.KeychainModule.clear(this.serviceName);
256
- } else {
257
- throw new Error("Keychain not available on this platform");
263
+ /**
264
+ * Get transaction status by hash
265
+ * Fetches from blockchain explorers to check confirmation status
266
+ */
267
+ async getTransactionStatus(txHash, chain, network = "testnet") {
268
+ try {
269
+ const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/tx-status`, {
270
+ method: "POST",
271
+ headers: {
272
+ "Content-Type": "application/json"
273
+ },
274
+ body: JSON.stringify({ txHash, chain, network })
275
+ });
276
+ return await response.json();
277
+ } catch (error) {
278
+ return {
279
+ success: false,
280
+ error: error instanceof Error ? error.message : "Failed to get transaction status"
281
+ };
258
282
  }
259
283
  }
260
284
  };
261
- var KeystoreStorageAdapter = class {
262
- alias;
263
- constructor(alias = "zubari_wallet_keys") {
264
- this.alias = alias;
285
+ var DEFAULT_API_URL = process.env.NEXT_PUBLIC_API_URL || "https://ckgwifsxka.us-east-2.awsapprunner.com";
286
+ var wdkApiClient = null;
287
+ function getWdkApiClient(baseUrl) {
288
+ if (!wdkApiClient || baseUrl && wdkApiClient["config"].baseUrl !== baseUrl) {
289
+ wdkApiClient = new WdkApiClient({
290
+ baseUrl: baseUrl || DEFAULT_API_URL
291
+ });
265
292
  }
266
- async setItem(key, value) {
267
- if (typeof global !== "undefined" && global.KeystoreModule) {
268
- await global.KeystoreModule.setItem(this.alias, key, value);
269
- } else {
270
- throw new Error("Keystore not available on this platform");
271
- }
272
- }
273
- async getItem(key) {
274
- if (typeof global !== "undefined" && global.KeystoreModule) {
275
- return global.KeystoreModule.getItem(this.alias, key);
276
- }
277
- throw new Error("Keystore not available on this platform");
278
- }
279
- async removeItem(key) {
280
- if (typeof global !== "undefined" && global.KeystoreModule) {
281
- await global.KeystoreModule.removeItem(this.alias, key);
282
- } else {
283
- throw new Error("Keystore not available on this platform");
284
- }
285
- }
286
- async hasItem(key) {
287
- const value = await this.getItem(key);
288
- return value !== null;
289
- }
290
- async clear() {
291
- if (typeof global !== "undefined" && global.KeystoreModule) {
292
- await global.KeystoreModule.clear(this.alias);
293
- } else {
294
- throw new Error("Keystore not available on this platform");
293
+ return wdkApiClient;
294
+ }
295
+ var DERIVATION_PATHS2 = {
296
+ ethereum: "m/44'/60'/0'/0/0",
297
+ bitcoin_mainnet: "m/84'/0'/0'/0/0",
298
+ bitcoin_testnet: "m/84'/1'/0'/0/0",
299
+ ton: "m/44'/607'/0'/0'/0'",
300
+ tron: "m/44'/195'/0'/0/0",
301
+ solana: "m/44'/501'/0'/0'",
302
+ spark: "m/44'/998'/0'/0/0"
303
+ };
304
+ function deriveEthereumAddress(seed) {
305
+ const hdNode = HDNodeWallet.fromPhrase(seed, void 0, DERIVATION_PATHS2.ethereum);
306
+ return hdNode.address;
307
+ }
308
+ function deriveBitcoinAddress(seed, network = "testnet") {
309
+ try {
310
+ const seedBytes = mnemonicToSeedSync(seed);
311
+ const hdKey = HDKey.fromMasterSeed(seedBytes);
312
+ const path = network === "testnet" ? DERIVATION_PATHS2.bitcoin_testnet : DERIVATION_PATHS2.bitcoin_mainnet;
313
+ const child = hdKey.derive(path);
314
+ if (!child.publicKey) {
315
+ throw new Error("Failed to derive public key");
295
316
  }
317
+ const pubKeyHash = ripemd160(sha256(child.publicKey));
318
+ const witnessVersion = 0;
319
+ const words = bech32.toWords(pubKeyHash);
320
+ words.unshift(witnessVersion);
321
+ const hrp = network === "testnet" ? "tb" : "bc";
322
+ const address = bech32.encode(hrp, words);
323
+ return address;
324
+ } catch (error) {
325
+ console.error("Bitcoin address derivation failed:", error);
326
+ throw error;
296
327
  }
297
- };
298
- var WebEncryptedStorageAdapter = class {
299
- encryptionKey = null;
300
- storagePrefix;
301
- constructor(storagePrefix = "zubari_") {
302
- this.storagePrefix = storagePrefix;
328
+ }
329
+ async function deriveSolanaAddress(seed) {
330
+ try {
331
+ const [ed25519, nacl, bs58Module] = await Promise.all([
332
+ import('ed25519-hd-key'),
333
+ import('tweetnacl'),
334
+ import('bs58')
335
+ ]);
336
+ const bs58 = bs58Module.default || bs58Module;
337
+ const seedBytes = mnemonicToSeedSync(seed);
338
+ const derived = ed25519.derivePath(DERIVATION_PATHS2.solana, Buffer.from(seedBytes).toString("hex"));
339
+ const keypair = nacl.sign.keyPair.fromSeed(new Uint8Array(derived.key));
340
+ return bs58.encode(keypair.publicKey);
341
+ } catch (error) {
342
+ console.error("Solana address derivation failed:", error);
343
+ throw error;
303
344
  }
304
- /**
305
- * Initialize with a password-derived key
306
- */
307
- async initialize(password) {
308
- const encoder = new TextEncoder();
309
- const salt = this.getSalt();
310
- const keyMaterial = await crypto.subtle.importKey(
311
- "raw",
312
- encoder.encode(password),
313
- "PBKDF2",
314
- false,
315
- ["deriveKey"]
316
- );
317
- this.encryptionKey = await crypto.subtle.deriveKey(
318
- {
319
- name: "PBKDF2",
320
- salt: salt.buffer,
321
- iterations: 1e5,
322
- hash: "SHA-256"
323
- },
324
- keyMaterial,
325
- { name: "AES-GCM", length: 256 },
326
- false,
327
- ["encrypt", "decrypt"]
328
- );
345
+ }
346
+ async function deriveTonAddress(seed) {
347
+ try {
348
+ const [ed25519, nacl] = await Promise.all([
349
+ import('ed25519-hd-key'),
350
+ import('tweetnacl')
351
+ ]);
352
+ const seedBytes = mnemonicToSeedSync(seed);
353
+ const derived = ed25519.derivePath(DERIVATION_PATHS2.ton, Buffer.from(seedBytes).toString("hex"));
354
+ const keypair = nacl.sign.keyPair.fromSeed(new Uint8Array(derived.key));
355
+ const publicKey = keypair.publicKey;
356
+ const workchain = 0;
357
+ const flags = 17;
358
+ const hash = sha256(publicKey);
359
+ const addressData = new Uint8Array(34);
360
+ addressData[0] = flags;
361
+ addressData[1] = workchain;
362
+ addressData.set(hash, 2);
363
+ const crc = crc16(addressData);
364
+ const fullAddress = new Uint8Array(36);
365
+ fullAddress.set(addressData);
366
+ fullAddress[34] = crc >> 8 & 255;
367
+ fullAddress[35] = crc & 255;
368
+ const base64 = btoa(String.fromCharCode(...fullAddress)).replace(/\+/g, "-").replace(/\//g, "_");
369
+ return base64;
370
+ } catch (error) {
371
+ console.error("TON address derivation failed:", error);
372
+ throw error;
329
373
  }
330
- getSalt() {
331
- const saltKey = `${this.storagePrefix}salt`;
332
- let saltHex = localStorage.getItem(saltKey);
333
- if (!saltHex) {
334
- const salt = crypto.getRandomValues(new Uint8Array(16));
335
- saltHex = Array.from(salt).map((b) => b.toString(16).padStart(2, "0")).join("");
336
- localStorage.setItem(saltKey, saltHex);
374
+ }
375
+ function crc16(data) {
376
+ let crc = 0;
377
+ for (const byte of data) {
378
+ crc ^= byte << 8;
379
+ for (let i = 0; i < 8; i++) {
380
+ crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
381
+ crc &= 65535;
337
382
  }
338
- return new Uint8Array(
339
- saltHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
340
- );
341
383
  }
342
- async setItem(key, value) {
343
- if (!this.encryptionKey) {
344
- throw new Error("Storage not initialized. Call initialize() first.");
384
+ return crc;
385
+ }
386
+ function deriveTronAddress(seed) {
387
+ try {
388
+ const hdNode = HDNodeWallet.fromPhrase(seed, void 0, DERIVATION_PATHS2.tron);
389
+ const ethAddressHex = hdNode.address.slice(2).toLowerCase();
390
+ const addressBytes = new Uint8Array(21);
391
+ addressBytes[0] = 65;
392
+ for (let i = 0; i < 20; i++) {
393
+ addressBytes[i + 1] = parseInt(ethAddressHex.slice(i * 2, i * 2 + 2), 16);
345
394
  }
346
- const encoder = new TextEncoder();
347
- const iv = crypto.getRandomValues(new Uint8Array(12));
348
- const encrypted = await crypto.subtle.encrypt(
349
- { name: "AES-GCM", iv },
350
- this.encryptionKey,
351
- encoder.encode(value)
352
- );
353
- const combined = new Uint8Array(iv.length + encrypted.byteLength);
354
- combined.set(iv);
355
- combined.set(new Uint8Array(encrypted), iv.length);
356
- const base64 = btoa(String.fromCharCode(...combined));
357
- localStorage.setItem(`${this.storagePrefix}${key}`, base64);
395
+ const tronBase58check = base58check(sha256);
396
+ return tronBase58check.encode(addressBytes);
397
+ } catch (error) {
398
+ console.error("TRON address derivation failed:", error);
399
+ throw error;
358
400
  }
359
- async getItem(key) {
360
- if (!this.encryptionKey) {
361
- throw new Error("Storage not initialized. Call initialize() first.");
362
- }
363
- const base64 = localStorage.getItem(`${this.storagePrefix}${key}`);
364
- if (!base64) return null;
365
- try {
366
- const combined = new Uint8Array(
367
- atob(base64).split("").map((c) => c.charCodeAt(0))
368
- );
369
- const iv = combined.slice(0, 12);
370
- const encrypted = combined.slice(12);
371
- const decrypted = await crypto.subtle.decrypt(
372
- { name: "AES-GCM", iv },
373
- this.encryptionKey,
374
- encrypted
375
- );
376
- const decoder = new TextDecoder();
377
- return decoder.decode(decrypted);
378
- } catch {
379
- return null;
401
+ }
402
+ function deriveSparkAddress(seed, network = "testnet") {
403
+ try {
404
+ const seedBytes = mnemonicToSeedSync(seed);
405
+ const hdKey = HDKey.fromMasterSeed(seedBytes);
406
+ const child = hdKey.derive(DERIVATION_PATHS2.spark);
407
+ if (!child.publicKey) {
408
+ throw new Error("Failed to derive public key");
380
409
  }
410
+ const pubKeyHash = ripemd160(sha256(child.publicKey));
411
+ const witnessVersion = 0;
412
+ const words = bech32.toWords(pubKeyHash);
413
+ words.unshift(witnessVersion);
414
+ const hrp = network === "testnet" ? "tsp" : "sp";
415
+ const address = bech32.encode(hrp, words);
416
+ return address;
417
+ } catch (error) {
418
+ console.error("Spark address derivation failed:", error);
419
+ throw error;
381
420
  }
382
- async removeItem(key) {
383
- localStorage.removeItem(`${this.storagePrefix}${key}`);
384
- }
385
- async hasItem(key) {
386
- return localStorage.getItem(`${this.storagePrefix}${key}`) !== null;
387
- }
388
- async clear() {
389
- const keysToRemove = [];
390
- for (let i = 0; i < localStorage.length; i++) {
391
- const key = localStorage.key(i);
392
- if (key?.startsWith(this.storagePrefix)) {
393
- keysToRemove.push(key);
394
- }
395
- }
396
- keysToRemove.forEach((key) => localStorage.removeItem(key));
421
+ }
422
+ async function deriveAllAddresses(seed, network = "testnet") {
423
+ const addresses = {
424
+ ethereum: null,
425
+ bitcoin: null,
426
+ ton: null,
427
+ tron: null,
428
+ solana: null,
429
+ spark: null
430
+ };
431
+ try {
432
+ addresses.ethereum = deriveEthereumAddress(seed);
433
+ } catch (e) {
434
+ console.error("ETH derivation failed:", e);
397
435
  }
398
- };
399
- var MemoryStorageAdapter = class {
400
- storage = /* @__PURE__ */ new Map();
401
- async setItem(key, value) {
402
- this.storage.set(key, value);
436
+ try {
437
+ addresses.bitcoin = deriveBitcoinAddress(seed, network);
438
+ } catch (e) {
439
+ console.error("BTC derivation failed:", e);
403
440
  }
404
- async getItem(key) {
405
- return this.storage.get(key) || null;
441
+ try {
442
+ addresses.spark = deriveSparkAddress(seed, network);
443
+ } catch (e) {
444
+ console.error("Spark derivation failed:", e);
406
445
  }
407
- async removeItem(key) {
408
- this.storage.delete(key);
446
+ try {
447
+ addresses.tron = deriveTronAddress(seed);
448
+ } catch (e) {
449
+ console.error("TRON derivation failed:", e);
409
450
  }
410
- async hasItem(key) {
411
- return this.storage.has(key);
451
+ const [solResult, tonResult] = await Promise.allSettled([
452
+ deriveSolanaAddress(seed),
453
+ deriveTonAddress(seed)
454
+ ]);
455
+ if (solResult.status === "fulfilled") {
456
+ addresses.solana = solResult.value;
457
+ } else {
458
+ console.error("SOL derivation failed:", solResult.reason);
412
459
  }
413
- async clear() {
414
- this.storage.clear();
460
+ if (tonResult.status === "fulfilled") {
461
+ addresses.ton = tonResult.value;
462
+ } else {
463
+ console.error("TON derivation failed:", tonResult.reason);
415
464
  }
416
- };
417
- function createSecureStorage() {
418
- if (typeof global !== "undefined" && global.nativeModuleProxy !== void 0) {
419
- const Platform = global.Platform;
420
- if (Platform?.OS === "ios") {
421
- return new KeychainStorageAdapter();
422
- } else if (Platform?.OS === "android") {
423
- return new KeystoreStorageAdapter();
424
- }
465
+ return addresses;
466
+ }
467
+ function isValidSeed(seed) {
468
+ return validateMnemonic(seed, wordlist);
469
+ }
470
+ function generateSeedPhrase() {
471
+ return generateMnemonic(wordlist);
472
+ }
473
+
474
+ // src/services/ZubariWdkService.ts
475
+ var DEFAULT_API_URL2 = "https://ckgwifsxka.us-east-2.awsapprunner.com";
476
+ function isBrowser() {
477
+ return typeof window !== "undefined" && typeof window.document !== "undefined";
478
+ }
479
+ var dynamicImport = new Function("specifier", "return import(specifier)");
480
+ async function canUseNativeWdk() {
481
+ if (isBrowser()) {
482
+ return false;
425
483
  }
426
- if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
427
- return new WebEncryptedStorageAdapter();
484
+ try {
485
+ await dynamicImport("@tetherto/wdk");
486
+ return true;
487
+ } catch {
488
+ return false;
428
489
  }
429
- return new MemoryStorageAdapter();
430
490
  }
431
-
432
- // src/services/WdkApiClient.ts
433
- var WdkApiClient = class {
491
+ var ZubariWdkService = class {
434
492
  config;
435
- constructor(config) {
493
+ apiClient;
494
+ nativeWdkService = null;
495
+ initialized = false;
496
+ useNativeWdk = false;
497
+ constructor(config = {}) {
436
498
  this.config = {
437
- baseUrl: config.baseUrl,
499
+ network: config.network || "testnet",
500
+ apiUrl: config.apiUrl || process.env.NEXT_PUBLIC_API_URL || DEFAULT_API_URL2,
501
+ forceApi: config.forceApi ?? false,
438
502
  timeout: config.timeout || 3e4
439
503
  };
504
+ this.apiClient = getWdkApiClient(this.config.apiUrl);
440
505
  }
441
506
  /**
442
- * Generate a new BIP-39 seed phrase using Tether WDK
507
+ * Initialize the service and determine the best strategy
508
+ */
509
+ async initialize() {
510
+ if (this.initialized) return;
511
+ if (isBrowser() || this.config.forceApi) {
512
+ this.useNativeWdk = false;
513
+ this.initialized = true;
514
+ return;
515
+ }
516
+ if (await canUseNativeWdk()) {
517
+ try {
518
+ const WdkServiceModule = await dynamicImport("./WdkService");
519
+ const WdkService = WdkServiceModule.WdkService || WdkServiceModule.default;
520
+ this.nativeWdkService = new WdkService({
521
+ network: this.config.network
522
+ });
523
+ this.useNativeWdk = true;
524
+ } catch (error) {
525
+ console.warn("Failed to initialize native WDK, falling back to API:", error);
526
+ this.useNativeWdk = false;
527
+ }
528
+ }
529
+ this.initialized = true;
530
+ }
531
+ /**
532
+ * Get the current execution mode
533
+ */
534
+ getMode() {
535
+ if (this.useNativeWdk) return "native";
536
+ if (isBrowser()) return "api";
537
+ return "api";
538
+ }
539
+ /**
540
+ * Check if running in browser
541
+ */
542
+ isBrowserEnvironment() {
543
+ return isBrowser();
544
+ }
545
+ /**
546
+ * Generate a new BIP-39 seed phrase (12 words)
443
547
  */
444
548
  async generateSeed() {
549
+ await this.initialize();
445
550
  try {
446
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/generate-seed`, {
447
- method: "POST",
448
- headers: {
449
- "Content-Type": "application/json"
450
- }
451
- });
452
- return await response.json();
551
+ const response = await this.apiClient.generateSeed();
552
+ if (response.success && response.seed) {
553
+ return response.seed;
554
+ }
453
555
  } catch (error) {
454
- return {
455
- success: false,
456
- error: error instanceof Error ? error.message : "Failed to generate seed"
457
- };
556
+ console.warn("API seed generation failed:", error);
458
557
  }
558
+ if (this.useNativeWdk && this.nativeWdkService) {
559
+ try {
560
+ const wdk = this.nativeWdkService;
561
+ return await wdk.generateSeedPhrase();
562
+ } catch (error) {
563
+ console.warn("Native WDK seed generation failed:", error);
564
+ }
565
+ }
566
+ return generateSeedPhrase();
459
567
  }
460
568
  /**
461
569
  * Validate a BIP-39 seed phrase
462
570
  */
463
571
  async validateSeed(seed) {
572
+ await this.initialize();
464
573
  try {
465
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/validate-seed`, {
466
- method: "POST",
467
- headers: {
468
- "Content-Type": "application/json"
469
- },
470
- body: JSON.stringify({ seed })
471
- });
472
- return await response.json();
574
+ const response = await this.apiClient.validateSeed(seed);
575
+ if (response.success) {
576
+ return response.isValid ?? false;
577
+ }
473
578
  } catch (error) {
474
- return {
475
- success: false,
476
- error: error instanceof Error ? error.message : "Failed to validate seed"
477
- };
579
+ console.warn("API seed validation failed:", error);
580
+ }
581
+ if (this.useNativeWdk && this.nativeWdkService) {
582
+ try {
583
+ const wdk = this.nativeWdkService;
584
+ return await wdk.isValidSeed(seed);
585
+ } catch (error) {
586
+ console.warn("Native WDK seed validation failed:", error);
587
+ }
478
588
  }
589
+ return isValidSeed(seed);
479
590
  }
480
591
  /**
481
- * Derive address for a specific chain using Tether WDK
592
+ * Derive address for a specific chain using WDK API
593
+ *
594
+ * For Ethereum, falls back to local derivation if API fails.
595
+ * For other chains, WDK API is required - no placeholder fallback.
482
596
  */
483
- async deriveAddress(seed, chain, network = "testnet") {
597
+ async deriveAddress(seed, chain) {
598
+ await this.initialize();
599
+ const path = this.getDerivationPath(chain);
484
600
  try {
485
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/derive-address`, {
486
- method: "POST",
487
- headers: {
488
- "Content-Type": "application/json"
489
- },
490
- body: JSON.stringify({ seed, chain, network })
491
- });
492
- return await response.json();
601
+ const response = await this.apiClient.deriveAddress(seed, chain, this.config.network);
602
+ if (response.success && response.address) {
603
+ return {
604
+ chain,
605
+ address: response.address,
606
+ path: response.path || path
607
+ };
608
+ }
609
+ } catch (error) {
610
+ console.warn(`API address derivation failed for ${chain}:`, error);
611
+ if (chain === "ethereum") {
612
+ return this.deriveBrowserAddress(seed, chain);
613
+ }
614
+ }
615
+ if (this.useNativeWdk && this.nativeWdkService) {
616
+ try {
617
+ const wdk = this.nativeWdkService;
618
+ await wdk.initialize(seed);
619
+ return await wdk.deriveAddress(chain);
620
+ } catch (error) {
621
+ console.warn(`Native WDK address derivation failed for ${chain}:`, error);
622
+ }
623
+ }
624
+ if (chain === "ethereum") {
625
+ return this.deriveBrowserAddress(seed, chain);
626
+ }
627
+ throw new Error(
628
+ `WDK API required for ${chain} address derivation. Ensure the backend is running.`
629
+ );
630
+ }
631
+ /**
632
+ * Derive addresses for all supported chains using WDK API
633
+ *
634
+ * Uses the backend WDK API for real cryptographically valid addresses.
635
+ * No placeholder fallback - WDK API is required for multi-chain addresses.
636
+ */
637
+ async deriveAllAddresses(seed) {
638
+ await this.initialize();
639
+ try {
640
+ const response = await this.apiClient.deriveAllAddresses(seed, this.config.network);
641
+ if (response.success && response.addresses) {
642
+ const extractAddress = (value) => {
643
+ if (!value) return null;
644
+ if (typeof value === "string") return value;
645
+ if (typeof value === "object" && value !== null && "address" in value) {
646
+ return value.address;
647
+ }
648
+ return null;
649
+ };
650
+ return {
651
+ ethereum: extractAddress(response.addresses.ethereum),
652
+ bitcoin: extractAddress(response.addresses.bitcoin),
653
+ ton: extractAddress(response.addresses.ton),
654
+ tron: extractAddress(response.addresses.tron),
655
+ solana: extractAddress(response.addresses.solana),
656
+ spark: extractAddress(response.addresses.spark)
657
+ };
658
+ }
493
659
  } catch (error) {
494
- return {
495
- success: false,
496
- error: error instanceof Error ? error.message : "Failed to derive address"
497
- };
660
+ console.warn("API address derivation failed:", error);
661
+ }
662
+ if (this.useNativeWdk && this.nativeWdkService) {
663
+ try {
664
+ const wdk = this.nativeWdkService;
665
+ await wdk.initialize(seed);
666
+ return await wdk.deriveAllAddresses();
667
+ } catch (error) {
668
+ console.warn("Native WDK multi-chain derivation failed:", error);
669
+ }
498
670
  }
671
+ throw new Error(
672
+ "Tether WDK API required for multi-chain address derivation. Service temporarily unavailable."
673
+ );
499
674
  }
500
675
  /**
501
- * Derive addresses for all chains using Tether WDK
676
+ * Get balances for all chains
502
677
  */
503
- async deriveAllAddresses(seed, network = "testnet") {
678
+ async getAllBalances(seed) {
679
+ await this.initialize();
504
680
  try {
505
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/derive-all`, {
681
+ const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/balances`, {
506
682
  method: "POST",
507
- headers: {
508
- "Content-Type": "application/json"
509
- },
510
- body: JSON.stringify({ seed, network })
683
+ headers: { "Content-Type": "application/json" },
684
+ body: JSON.stringify({ seed, network: this.config.network })
511
685
  });
512
- return await response.json();
686
+ if (response.ok) {
687
+ const data = await response.json();
688
+ if (data.success) {
689
+ return data.balances;
690
+ }
691
+ }
513
692
  } catch (error) {
514
- return {
515
- success: false,
516
- error: error instanceof Error ? error.message : "Failed to derive addresses"
517
- };
693
+ console.warn("Failed to fetch balances:", error);
518
694
  }
695
+ return {};
519
696
  }
520
697
  /**
521
- * Send a transaction on a specific chain using Tether WDK
698
+ * Get fee rates for a chain
522
699
  */
523
- async sendTransaction(seed, chain, to, amount, network = "testnet") {
700
+ async getFeeRates(seed, chain) {
701
+ await this.initialize();
524
702
  try {
525
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/send`, {
703
+ const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/fee-rates`, {
526
704
  method: "POST",
527
- headers: {
528
- "Content-Type": "application/json"
529
- },
530
- body: JSON.stringify({ seed, chain, to, amount, network })
705
+ headers: { "Content-Type": "application/json" },
706
+ body: JSON.stringify({ seed, chain, network: this.config.network })
531
707
  });
532
- return await response.json();
708
+ if (response.ok) {
709
+ const data = await response.json();
710
+ if (data.success && data.feeRates) {
711
+ return data.feeRates;
712
+ }
713
+ }
533
714
  } catch (error) {
534
- return {
535
- success: false,
536
- error: error instanceof Error ? error.message : "Failed to send transaction"
537
- };
715
+ console.warn(`Failed to fetch fee rates for ${chain}:`, error);
538
716
  }
717
+ return { slow: "0", normal: "0", fast: "0" };
539
718
  }
540
719
  /**
541
- * Get transaction history for an address on a specific chain
542
- * Fetches from blockchain explorers (Etherscan, mempool.space, etc.)
720
+ * Estimate transaction fee
543
721
  */
544
- async getTransactionHistory(seed, chain, network = "testnet", limit = 10) {
722
+ async estimateFee(seed, chain, to, amount) {
723
+ await this.initialize();
545
724
  try {
546
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/history`, {
725
+ const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/estimate-fee`, {
547
726
  method: "POST",
548
- headers: {
549
- "Content-Type": "application/json"
550
- },
551
- body: JSON.stringify({ seed, chain, network, limit })
727
+ headers: { "Content-Type": "application/json" },
728
+ body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
552
729
  });
553
- return await response.json();
730
+ if (response.ok) {
731
+ const data = await response.json();
732
+ if (data.success) {
733
+ return { fee: data.fee, symbol: data.symbol };
734
+ }
735
+ }
554
736
  } catch (error) {
555
- return {
556
- success: false,
557
- error: error instanceof Error ? error.message : "Failed to get transaction history"
558
- };
737
+ console.warn(`Failed to estimate fee for ${chain}:`, error);
559
738
  }
739
+ return { fee: "0", symbol: this.getChainSymbol(chain) };
560
740
  }
561
741
  /**
562
- * Get transaction status by hash
563
- * Fetches from blockchain explorers to check confirmation status
742
+ * Send a transaction
564
743
  */
565
- async getTransactionStatus(txHash, chain, network = "testnet") {
744
+ async sendTransaction(seed, chain, to, amount) {
745
+ await this.initialize();
566
746
  try {
567
- const response = await fetch(`${this.config.baseUrl}/api/wallets/wdk/tx-status`, {
747
+ const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/send`, {
568
748
  method: "POST",
569
- headers: {
570
- "Content-Type": "application/json"
571
- },
572
- body: JSON.stringify({ txHash, chain, network })
749
+ headers: { "Content-Type": "application/json" },
750
+ body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
573
751
  });
574
- return await response.json();
575
- } catch (error) {
576
- return {
577
- success: false,
578
- error: error instanceof Error ? error.message : "Failed to get transaction status"
579
- };
580
- }
581
- }
582
- };
583
- var DEFAULT_API_URL = process.env.NEXT_PUBLIC_API_URL || "https://ckgwifsxka.us-east-2.awsapprunner.com";
584
- var wdkApiClient = null;
585
- function getWdkApiClient(baseUrl) {
586
- if (!wdkApiClient || baseUrl && wdkApiClient["config"].baseUrl !== baseUrl) {
587
- wdkApiClient = new WdkApiClient({
588
- baseUrl: baseUrl || DEFAULT_API_URL
589
- });
590
- }
591
- return wdkApiClient;
592
- }
593
- var DERIVATION_PATHS2 = {
594
- ethereum: "m/44'/60'/0'/0/0",
595
- bitcoin_mainnet: "m/84'/0'/0'/0/0",
596
- bitcoin_testnet: "m/84'/1'/0'/0/0",
597
- ton: "m/44'/607'/0'/0'/0'",
598
- tron: "m/44'/195'/0'/0/0",
599
- solana: "m/44'/501'/0'/0'",
600
- spark: "m/44'/998'/0'/0/0"
601
- };
602
- function deriveEthereumAddress(seed) {
603
- const hdNode = HDNodeWallet.fromPhrase(seed, void 0, DERIVATION_PATHS2.ethereum);
604
- return hdNode.address;
605
- }
606
- function deriveBitcoinAddress(seed, network = "testnet") {
607
- try {
608
- const seedBytes = mnemonicToSeedSync(seed);
609
- const hdKey = HDKey.fromMasterSeed(seedBytes);
610
- const path = network === "testnet" ? DERIVATION_PATHS2.bitcoin_testnet : DERIVATION_PATHS2.bitcoin_mainnet;
611
- const child = hdKey.derive(path);
612
- if (!child.publicKey) {
613
- throw new Error("Failed to derive public key");
614
- }
615
- const pubKeyHash = ripemd160(sha256(child.publicKey));
616
- const witnessVersion = 0;
617
- const words = bech32.toWords(pubKeyHash);
618
- words.unshift(witnessVersion);
619
- const hrp = network === "testnet" ? "tb" : "bc";
620
- const address = bech32.encode(hrp, words);
621
- return address;
622
- } catch (error) {
623
- console.error("Bitcoin address derivation failed:", error);
624
- throw error;
625
- }
626
- }
627
- async function deriveSolanaAddress(seed) {
628
- try {
629
- const [ed25519, nacl, bs58Module] = await Promise.all([
630
- import('ed25519-hd-key'),
631
- import('tweetnacl'),
632
- import('bs58')
633
- ]);
634
- const bs58 = bs58Module.default || bs58Module;
635
- const seedBytes = mnemonicToSeedSync(seed);
636
- const derived = ed25519.derivePath(DERIVATION_PATHS2.solana, Buffer.from(seedBytes).toString("hex"));
637
- const keypair = nacl.sign.keyPair.fromSeed(new Uint8Array(derived.key));
638
- return bs58.encode(keypair.publicKey);
639
- } catch (error) {
640
- console.error("Solana address derivation failed:", error);
641
- throw error;
642
- }
643
- }
644
- async function deriveTonAddress(seed) {
645
- try {
646
- const [ed25519, nacl] = await Promise.all([
647
- import('ed25519-hd-key'),
648
- import('tweetnacl')
649
- ]);
650
- const seedBytes = mnemonicToSeedSync(seed);
651
- const derived = ed25519.derivePath(DERIVATION_PATHS2.ton, Buffer.from(seedBytes).toString("hex"));
652
- const keypair = nacl.sign.keyPair.fromSeed(new Uint8Array(derived.key));
653
- const publicKey = keypair.publicKey;
654
- const workchain = 0;
655
- const flags = 17;
656
- const hash = sha256(publicKey);
657
- const addressData = new Uint8Array(34);
658
- addressData[0] = flags;
659
- addressData[1] = workchain;
660
- addressData.set(hash, 2);
661
- const crc = crc16(addressData);
662
- const fullAddress = new Uint8Array(36);
663
- fullAddress.set(addressData);
664
- fullAddress[34] = crc >> 8 & 255;
665
- fullAddress[35] = crc & 255;
666
- const base64 = btoa(String.fromCharCode(...fullAddress)).replace(/\+/g, "-").replace(/\//g, "_");
667
- return base64;
668
- } catch (error) {
669
- console.error("TON address derivation failed:", error);
670
- throw error;
671
- }
672
- }
673
- function crc16(data) {
674
- let crc = 0;
675
- for (const byte of data) {
676
- crc ^= byte << 8;
677
- for (let i = 0; i < 8; i++) {
678
- crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
679
- crc &= 65535;
680
- }
681
- }
682
- return crc;
683
- }
684
- function deriveTronAddress(seed) {
685
- try {
686
- const hdNode = HDNodeWallet.fromPhrase(seed, void 0, DERIVATION_PATHS2.tron);
687
- const ethAddressHex = hdNode.address.slice(2).toLowerCase();
688
- const addressBytes = new Uint8Array(21);
689
- addressBytes[0] = 65;
690
- for (let i = 0; i < 20; i++) {
691
- addressBytes[i + 1] = parseInt(ethAddressHex.slice(i * 2, i * 2 + 2), 16);
752
+ if (response.ok) {
753
+ const data = await response.json();
754
+ let txHash = data.txHash || data.transactionHash || data.hash;
755
+ if (txHash && typeof txHash === "object" && "hash" in txHash) {
756
+ txHash = txHash.hash;
757
+ }
758
+ if (chain === "ethereum" && txHash && (typeof txHash !== "string" || !txHash.startsWith("0x") || txHash.length !== 66)) {
759
+ console.warn(`Invalid Ethereum tx hash format: ${txHash} (length: ${txHash?.length}, expected: 66)`);
760
+ }
761
+ return {
762
+ success: data.success,
763
+ txHash,
764
+ from: data.from,
765
+ to: data.to,
766
+ amount: data.amount,
767
+ chain: data.chain,
768
+ network: data.network
769
+ };
770
+ }
771
+ const errorData = await response.json().catch(() => ({}));
772
+ return {
773
+ success: false,
774
+ error: errorData.error || `HTTP ${response.status}`
775
+ };
776
+ } catch (error) {
777
+ return {
778
+ success: false,
779
+ error: error instanceof Error ? error.message : "Transaction failed"
780
+ };
692
781
  }
693
- const tronBase58check = base58check(sha256);
694
- return tronBase58check.encode(addressBytes);
695
- } catch (error) {
696
- console.error("TRON address derivation failed:", error);
697
- throw error;
698
782
  }
699
- }
700
- function deriveSparkAddress(seed, network = "testnet") {
701
- try {
702
- const seedBytes = mnemonicToSeedSync(seed);
703
- const hdKey = HDKey.fromMasterSeed(seedBytes);
704
- const child = hdKey.derive(DERIVATION_PATHS2.spark);
705
- if (!child.publicKey) {
706
- throw new Error("Failed to derive public key");
707
- }
708
- const pubKeyHash = ripemd160(sha256(child.publicKey));
709
- const witnessVersion = 0;
710
- const words = bech32.toWords(pubKeyHash);
711
- words.unshift(witnessVersion);
712
- const hrp = network === "testnet" ? "tsp" : "sp";
713
- const address = bech32.encode(hrp, words);
714
- return address;
715
- } catch (error) {
716
- console.error("Spark address derivation failed:", error);
717
- throw error;
783
+ /**
784
+ * Get the network configuration
785
+ */
786
+ getNetwork() {
787
+ return this.config.network;
718
788
  }
719
- }
720
- async function deriveAllAddresses(seed, network = "testnet") {
721
- const addresses = {
722
- ethereum: null,
723
- bitcoin: null,
724
- ton: null,
725
- tron: null,
726
- solana: null,
727
- spark: null
728
- };
729
- try {
730
- addresses.ethereum = deriveEthereumAddress(seed);
731
- } catch (e) {
732
- console.error("ETH derivation failed:", e);
789
+ /**
790
+ * Get API URL
791
+ */
792
+ getApiUrl() {
793
+ return this.config.apiUrl;
733
794
  }
734
- try {
735
- addresses.bitcoin = deriveBitcoinAddress(seed, network);
736
- } catch (e) {
737
- console.error("BTC derivation failed:", e);
795
+ // ==========================================
796
+ // Private Helper Methods
797
+ // ==========================================
798
+ getDerivationPath(chain) {
799
+ const paths = {
800
+ bitcoin: this.config.network === "testnet" ? "m/84'/1'/0'/0/0" : "m/84'/0'/0'/0/0",
801
+ ethereum: "m/44'/60'/0'/0/0",
802
+ ton: "m/44'/607'/0'/0'/0'",
803
+ tron: "m/44'/195'/0'/0/0",
804
+ solana: "m/44'/501'/0'/0'",
805
+ spark: "m/44'/998'/0'/0/0"
806
+ };
807
+ return paths[chain];
738
808
  }
739
- try {
740
- addresses.spark = deriveSparkAddress(seed, network);
741
- } catch (e) {
742
- console.error("Spark derivation failed:", e);
809
+ getChainSymbol(chain) {
810
+ const symbols = {
811
+ ethereum: "ETH",
812
+ bitcoin: "BTC",
813
+ ton: "TON",
814
+ tron: "TRX",
815
+ solana: "SOL",
816
+ spark: "SAT"
817
+ };
818
+ return symbols[chain];
743
819
  }
744
- try {
745
- addresses.tron = deriveTronAddress(seed);
746
- } catch (e) {
747
- console.error("TRON derivation failed:", e);
820
+ /**
821
+ * Derive address using browser-compatible libraries
822
+ */
823
+ async deriveBrowserAddress(seed, chain) {
824
+ const path = this.getDerivationPath(chain);
825
+ try {
826
+ let address;
827
+ switch (chain) {
828
+ case "ethereum":
829
+ address = deriveEthereumAddress(seed);
830
+ break;
831
+ case "bitcoin":
832
+ address = deriveBitcoinAddress(seed, this.config.network);
833
+ break;
834
+ case "tron":
835
+ address = deriveTronAddress(seed);
836
+ break;
837
+ case "spark":
838
+ address = deriveSparkAddress(seed, this.config.network);
839
+ break;
840
+ case "solana":
841
+ address = await deriveSolanaAddress(seed);
842
+ break;
843
+ case "ton":
844
+ address = await deriveTonAddress(seed);
845
+ break;
846
+ default:
847
+ throw new Error(`Unsupported chain: ${chain}`);
848
+ }
849
+ return { chain, address, path };
850
+ } catch (error) {
851
+ console.error(`Browser derivation failed for ${chain}:`, error);
852
+ throw error;
853
+ }
748
854
  }
749
- const [solResult, tonResult] = await Promise.allSettled([
750
- deriveSolanaAddress(seed),
751
- deriveTonAddress(seed)
752
- ]);
753
- if (solResult.status === "fulfilled") {
754
- addresses.solana = solResult.value;
755
- } else {
756
- console.error("SOL derivation failed:", solResult.reason);
855
+ /**
856
+ * Derive all addresses using browser-compatible libraries
857
+ */
858
+ async deriveAllBrowserAddresses(seed) {
859
+ return deriveAllAddresses(seed, this.config.network);
757
860
  }
758
- if (tonResult.status === "fulfilled") {
759
- addresses.ton = tonResult.value;
760
- } else {
761
- console.error("TON derivation failed:", tonResult.reason);
861
+ };
862
+ var defaultService = null;
863
+ function getZubariWdkService(config) {
864
+ if (!defaultService || config && config.network !== defaultService.getNetwork()) {
865
+ defaultService = new ZubariWdkService(config);
762
866
  }
763
- return addresses;
764
- }
765
- function isValidSeed(seed) {
766
- return validateMnemonic(seed, wordlist);
767
- }
768
- function generateSeedPhrase() {
769
- return generateMnemonic(wordlist);
867
+ return defaultService;
770
868
  }
771
869
 
772
- // src/services/ZubariWdkService.ts
773
- var DEFAULT_API_URL2 = "https://ckgwifsxka.us-east-2.awsapprunner.com";
774
- function isBrowser() {
775
- return typeof window !== "undefined" && typeof window.document !== "undefined";
776
- }
777
- var dynamicImport = new Function("specifier", "return import(specifier)");
778
- async function canUseNativeWdk() {
779
- if (isBrowser()) {
780
- return false;
781
- }
782
- try {
783
- await dynamicImport("@tetherto/wdk");
784
- return true;
785
- } catch {
786
- return false;
787
- }
788
- }
789
- var ZubariWdkService = class {
790
- config;
791
- apiClient;
792
- nativeWdkService = null;
793
- initialized = false;
794
- useNativeWdk = false;
795
- constructor(config = {}) {
796
- this.config = {
797
- network: config.network || "testnet",
798
- apiUrl: config.apiUrl || process.env.NEXT_PUBLIC_API_URL || DEFAULT_API_URL2,
799
- forceApi: config.forceApi ?? false,
800
- timeout: config.timeout || 3e4
801
- };
802
- this.apiClient = getWdkApiClient(this.config.apiUrl);
870
+ // src/security/KeyManager.ts
871
+ var KeyManager = class {
872
+ static ALGORITHM = "AES-GCM";
873
+ static KEY_LENGTH = 256;
874
+ static IV_LENGTH = 12;
875
+ static SALT_LENGTH = 16;
876
+ static PBKDF2_ITERATIONS = 1e5;
877
+ /**
878
+ * Encrypt a seed phrase with a password
879
+ */
880
+ static async encryptSeed(seed, password) {
881
+ const encoder = new TextEncoder();
882
+ const seedData = encoder.encode(seed);
883
+ const salt = crypto.getRandomValues(new Uint8Array(this.SALT_LENGTH));
884
+ const iv = crypto.getRandomValues(new Uint8Array(this.IV_LENGTH));
885
+ const key = await this.deriveKey(password, salt);
886
+ const encrypted = await crypto.subtle.encrypt(
887
+ { name: this.ALGORITHM, iv },
888
+ key,
889
+ seedData
890
+ );
891
+ const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength);
892
+ combined.set(salt, 0);
893
+ combined.set(iv, salt.length);
894
+ combined.set(new Uint8Array(encrypted), salt.length + iv.length);
895
+ return btoa(String.fromCharCode(...combined));
803
896
  }
804
897
  /**
805
- * Initialize the service and determine the best strategy
898
+ * Decrypt a seed phrase with a password
806
899
  */
807
- async initialize() {
808
- if (this.initialized) return;
809
- if (isBrowser() || this.config.forceApi) {
810
- this.useNativeWdk = false;
811
- this.initialized = true;
812
- return;
813
- }
814
- if (await canUseNativeWdk()) {
815
- try {
816
- const WdkServiceModule = await dynamicImport("./WdkService");
817
- const WdkService = WdkServiceModule.WdkService || WdkServiceModule.default;
818
- this.nativeWdkService = new WdkService({
819
- network: this.config.network
820
- });
821
- this.useNativeWdk = true;
822
- } catch (error) {
823
- console.warn("Failed to initialize native WDK, falling back to API:", error);
824
- this.useNativeWdk = false;
825
- }
826
- }
827
- this.initialized = true;
900
+ static async decryptSeed(encryptedData, password) {
901
+ const combined = new Uint8Array(
902
+ atob(encryptedData).split("").map((c) => c.charCodeAt(0))
903
+ );
904
+ const salt = combined.slice(0, this.SALT_LENGTH);
905
+ const iv = combined.slice(this.SALT_LENGTH, this.SALT_LENGTH + this.IV_LENGTH);
906
+ const encrypted = combined.slice(this.SALT_LENGTH + this.IV_LENGTH);
907
+ const key = await this.deriveKey(password, salt);
908
+ const decrypted = await crypto.subtle.decrypt(
909
+ { name: this.ALGORITHM, iv },
910
+ key,
911
+ encrypted
912
+ );
913
+ const decoder = new TextDecoder();
914
+ return decoder.decode(decrypted);
828
915
  }
829
916
  /**
830
- * Get the current execution mode
917
+ * Derive encryption key from password using PBKDF2
831
918
  */
832
- getMode() {
833
- if (this.useNativeWdk) return "native";
834
- if (isBrowser()) return "api";
835
- return "api";
919
+ static async deriveKey(password, salt) {
920
+ const encoder = new TextEncoder();
921
+ const passwordData = encoder.encode(password);
922
+ const keyMaterial = await crypto.subtle.importKey(
923
+ "raw",
924
+ passwordData,
925
+ "PBKDF2",
926
+ false,
927
+ ["deriveKey"]
928
+ );
929
+ return crypto.subtle.deriveKey(
930
+ {
931
+ name: "PBKDF2",
932
+ salt: salt.buffer.slice(salt.byteOffset, salt.byteOffset + salt.byteLength),
933
+ iterations: this.PBKDF2_ITERATIONS,
934
+ hash: "SHA-256"
935
+ },
936
+ keyMaterial,
937
+ { name: this.ALGORITHM, length: this.KEY_LENGTH },
938
+ false,
939
+ ["encrypt", "decrypt"]
940
+ );
836
941
  }
837
942
  /**
838
- * Check if running in browser
943
+ * Validate a BIP-39 seed phrase (basic validation)
839
944
  */
840
- isBrowserEnvironment() {
841
- return isBrowser();
945
+ static validateSeedPhrase(seed) {
946
+ const words = seed.trim().split(/\s+/);
947
+ const validWordCounts = [12, 15, 18, 21, 24];
948
+ return validWordCounts.includes(words.length);
842
949
  }
843
950
  /**
844
- * Generate a new BIP-39 seed phrase (12 words)
951
+ * Generate a random encryption key (for backup purposes)
845
952
  */
846
- async generateSeed() {
847
- await this.initialize();
848
- try {
849
- const response = await this.apiClient.generateSeed();
850
- if (response.success && response.seed) {
851
- return response.seed;
852
- }
853
- } catch (error) {
854
- console.warn("API seed generation failed:", error);
953
+ static generateBackupKey() {
954
+ const bytes = crypto.getRandomValues(new Uint8Array(32));
955
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
956
+ }
957
+ };
958
+
959
+ // src/storage/SecureStorage.ts
960
+ var KeychainStorageAdapter = class {
961
+ serviceName;
962
+ constructor(serviceName = "com.zubari.wallet") {
963
+ this.serviceName = serviceName;
964
+ }
965
+ async setItem(key, value) {
966
+ if (typeof global !== "undefined" && global.KeychainModule) {
967
+ await global.KeychainModule.setItem(this.serviceName, key, value);
968
+ } else {
969
+ throw new Error("Keychain not available on this platform");
855
970
  }
856
- if (this.useNativeWdk && this.nativeWdkService) {
857
- try {
858
- const wdk = this.nativeWdkService;
859
- return await wdk.generateSeedPhrase();
860
- } catch (error) {
861
- console.warn("Native WDK seed generation failed:", error);
862
- }
971
+ }
972
+ async getItem(key) {
973
+ if (typeof global !== "undefined" && global.KeychainModule) {
974
+ return global.KeychainModule.getItem(this.serviceName, key);
863
975
  }
864
- return generateSeedPhrase();
976
+ throw new Error("Keychain not available on this platform");
865
977
  }
866
- /**
867
- * Validate a BIP-39 seed phrase
868
- */
869
- async validateSeed(seed) {
870
- await this.initialize();
871
- try {
872
- const response = await this.apiClient.validateSeed(seed);
873
- if (response.success) {
874
- return response.isValid ?? false;
875
- }
876
- } catch (error) {
877
- console.warn("API seed validation failed:", error);
978
+ async removeItem(key) {
979
+ if (typeof global !== "undefined" && global.KeychainModule) {
980
+ await global.KeychainModule.removeItem(this.serviceName, key);
981
+ } else {
982
+ throw new Error("Keychain not available on this platform");
878
983
  }
879
- if (this.useNativeWdk && this.nativeWdkService) {
880
- try {
881
- const wdk = this.nativeWdkService;
882
- return await wdk.isValidSeed(seed);
883
- } catch (error) {
884
- console.warn("Native WDK seed validation failed:", error);
885
- }
984
+ }
985
+ async hasItem(key) {
986
+ const value = await this.getItem(key);
987
+ return value !== null;
988
+ }
989
+ async clear() {
990
+ if (typeof global !== "undefined" && global.KeychainModule) {
991
+ await global.KeychainModule.clear(this.serviceName);
992
+ } else {
993
+ throw new Error("Keychain not available on this platform");
886
994
  }
887
- return isValidSeed(seed);
888
995
  }
889
- /**
890
- * Derive address for a specific chain using WDK API
891
- *
892
- * For Ethereum, falls back to local derivation if API fails.
893
- * For other chains, WDK API is required - no placeholder fallback.
894
- */
895
- async deriveAddress(seed, chain) {
896
- await this.initialize();
897
- const path = this.getDerivationPath(chain);
898
- try {
899
- const response = await this.apiClient.deriveAddress(seed, chain, this.config.network);
900
- if (response.success && response.address) {
901
- return {
902
- chain,
903
- address: response.address,
904
- path: response.path || path
905
- };
906
- }
907
- } catch (error) {
908
- console.warn(`API address derivation failed for ${chain}:`, error);
909
- if (chain === "ethereum") {
910
- return this.deriveBrowserAddress(seed, chain);
911
- }
996
+ };
997
+ var KeystoreStorageAdapter = class {
998
+ alias;
999
+ constructor(alias = "zubari_wallet_keys") {
1000
+ this.alias = alias;
1001
+ }
1002
+ async setItem(key, value) {
1003
+ if (typeof global !== "undefined" && global.KeystoreModule) {
1004
+ await global.KeystoreModule.setItem(this.alias, key, value);
1005
+ } else {
1006
+ throw new Error("Keystore not available on this platform");
912
1007
  }
913
- if (this.useNativeWdk && this.nativeWdkService) {
914
- try {
915
- const wdk = this.nativeWdkService;
916
- await wdk.initialize(seed);
917
- return await wdk.deriveAddress(chain);
918
- } catch (error) {
919
- console.warn(`Native WDK address derivation failed for ${chain}:`, error);
920
- }
1008
+ }
1009
+ async getItem(key) {
1010
+ if (typeof global !== "undefined" && global.KeystoreModule) {
1011
+ return global.KeystoreModule.getItem(this.alias, key);
921
1012
  }
922
- if (chain === "ethereum") {
923
- return this.deriveBrowserAddress(seed, chain);
1013
+ throw new Error("Keystore not available on this platform");
1014
+ }
1015
+ async removeItem(key) {
1016
+ if (typeof global !== "undefined" && global.KeystoreModule) {
1017
+ await global.KeystoreModule.removeItem(this.alias, key);
1018
+ } else {
1019
+ throw new Error("Keystore not available on this platform");
1020
+ }
1021
+ }
1022
+ async hasItem(key) {
1023
+ const value = await this.getItem(key);
1024
+ return value !== null;
1025
+ }
1026
+ async clear() {
1027
+ if (typeof global !== "undefined" && global.KeystoreModule) {
1028
+ await global.KeystoreModule.clear(this.alias);
1029
+ } else {
1030
+ throw new Error("Keystore not available on this platform");
924
1031
  }
925
- throw new Error(
926
- `WDK API required for ${chain} address derivation. Ensure the backend is running.`
927
- );
1032
+ }
1033
+ };
1034
+ var WebEncryptedStorageAdapter = class {
1035
+ encryptionKey = null;
1036
+ storagePrefix;
1037
+ constructor(storagePrefix = "zubari_") {
1038
+ this.storagePrefix = storagePrefix;
928
1039
  }
929
1040
  /**
930
- * Derive addresses for all supported chains using WDK API
931
- *
932
- * Uses the backend WDK API for real cryptographically valid addresses.
933
- * No placeholder fallback - WDK API is required for multi-chain addresses.
1041
+ * Initialize with a password-derived key
934
1042
  */
935
- async deriveAllAddresses(seed) {
936
- await this.initialize();
937
- try {
938
- const response = await this.apiClient.deriveAllAddresses(seed, this.config.network);
939
- if (response.success && response.addresses) {
940
- const extractAddress = (value) => {
941
- if (!value) return null;
942
- if (typeof value === "string") return value;
943
- if (typeof value === "object" && value !== null && "address" in value) {
944
- return value.address;
945
- }
946
- return null;
947
- };
948
- return {
949
- ethereum: extractAddress(response.addresses.ethereum),
950
- bitcoin: extractAddress(response.addresses.bitcoin),
951
- ton: extractAddress(response.addresses.ton),
952
- tron: extractAddress(response.addresses.tron),
953
- solana: extractAddress(response.addresses.solana),
954
- spark: extractAddress(response.addresses.spark)
955
- };
956
- }
957
- } catch (error) {
958
- console.warn("API address derivation failed:", error);
959
- }
960
- if (this.useNativeWdk && this.nativeWdkService) {
961
- try {
962
- const wdk = this.nativeWdkService;
963
- await wdk.initialize(seed);
964
- return await wdk.deriveAllAddresses();
965
- } catch (error) {
966
- console.warn("Native WDK multi-chain derivation failed:", error);
967
- }
1043
+ async initialize(password) {
1044
+ const encoder = new TextEncoder();
1045
+ const salt = this.getSalt();
1046
+ const keyMaterial = await crypto.subtle.importKey(
1047
+ "raw",
1048
+ encoder.encode(password),
1049
+ "PBKDF2",
1050
+ false,
1051
+ ["deriveKey"]
1052
+ );
1053
+ this.encryptionKey = await crypto.subtle.deriveKey(
1054
+ {
1055
+ name: "PBKDF2",
1056
+ salt: salt.buffer,
1057
+ iterations: 1e5,
1058
+ hash: "SHA-256"
1059
+ },
1060
+ keyMaterial,
1061
+ { name: "AES-GCM", length: 256 },
1062
+ false,
1063
+ ["encrypt", "decrypt"]
1064
+ );
1065
+ }
1066
+ getSalt() {
1067
+ const saltKey = `${this.storagePrefix}salt`;
1068
+ let saltHex = localStorage.getItem(saltKey);
1069
+ if (!saltHex) {
1070
+ const salt = crypto.getRandomValues(new Uint8Array(16));
1071
+ saltHex = Array.from(salt).map((b) => b.toString(16).padStart(2, "0")).join("");
1072
+ localStorage.setItem(saltKey, saltHex);
968
1073
  }
969
- throw new Error(
970
- "Tether WDK API required for multi-chain address derivation. Service temporarily unavailable."
1074
+ return new Uint8Array(
1075
+ saltHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
971
1076
  );
972
1077
  }
973
- /**
974
- * Get balances for all chains
975
- */
976
- async getAllBalances(seed) {
977
- await this.initialize();
978
- try {
979
- const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/balances`, {
980
- method: "POST",
981
- headers: { "Content-Type": "application/json" },
982
- body: JSON.stringify({ seed, network: this.config.network })
983
- });
984
- if (response.ok) {
985
- const data = await response.json();
986
- if (data.success) {
987
- return data.balances;
988
- }
989
- }
990
- } catch (error) {
991
- console.warn("Failed to fetch balances:", error);
1078
+ async setItem(key, value) {
1079
+ if (!this.encryptionKey) {
1080
+ throw new Error("Storage not initialized. Call initialize() first.");
992
1081
  }
993
- return {};
1082
+ const encoder = new TextEncoder();
1083
+ const iv = crypto.getRandomValues(new Uint8Array(12));
1084
+ const encrypted = await crypto.subtle.encrypt(
1085
+ { name: "AES-GCM", iv },
1086
+ this.encryptionKey,
1087
+ encoder.encode(value)
1088
+ );
1089
+ const combined = new Uint8Array(iv.length + encrypted.byteLength);
1090
+ combined.set(iv);
1091
+ combined.set(new Uint8Array(encrypted), iv.length);
1092
+ const base64 = btoa(String.fromCharCode(...combined));
1093
+ localStorage.setItem(`${this.storagePrefix}${key}`, base64);
994
1094
  }
995
- /**
996
- * Get fee rates for a chain
997
- */
998
- async getFeeRates(seed, chain) {
999
- await this.initialize();
1000
- try {
1001
- const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/fee-rates`, {
1002
- method: "POST",
1003
- headers: { "Content-Type": "application/json" },
1004
- body: JSON.stringify({ seed, chain, network: this.config.network })
1005
- });
1006
- if (response.ok) {
1007
- const data = await response.json();
1008
- if (data.success && data.feeRates) {
1009
- return data.feeRates;
1010
- }
1011
- }
1012
- } catch (error) {
1013
- console.warn(`Failed to fetch fee rates for ${chain}:`, error);
1095
+ async getItem(key) {
1096
+ if (!this.encryptionKey) {
1097
+ throw new Error("Storage not initialized. Call initialize() first.");
1014
1098
  }
1015
- return { slow: "0", normal: "0", fast: "0" };
1016
- }
1017
- /**
1018
- * Estimate transaction fee
1019
- */
1020
- async estimateFee(seed, chain, to, amount) {
1021
- await this.initialize();
1099
+ const base64 = localStorage.getItem(`${this.storagePrefix}${key}`);
1100
+ if (!base64) return null;
1022
1101
  try {
1023
- const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/estimate-fee`, {
1024
- method: "POST",
1025
- headers: { "Content-Type": "application/json" },
1026
- body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
1027
- });
1028
- if (response.ok) {
1029
- const data = await response.json();
1030
- if (data.success) {
1031
- return { fee: data.fee, symbol: data.symbol };
1032
- }
1033
- }
1034
- } catch (error) {
1035
- console.warn(`Failed to estimate fee for ${chain}:`, error);
1102
+ const combined = new Uint8Array(
1103
+ atob(base64).split("").map((c) => c.charCodeAt(0))
1104
+ );
1105
+ const iv = combined.slice(0, 12);
1106
+ const encrypted = combined.slice(12);
1107
+ const decrypted = await crypto.subtle.decrypt(
1108
+ { name: "AES-GCM", iv },
1109
+ this.encryptionKey,
1110
+ encrypted
1111
+ );
1112
+ const decoder = new TextDecoder();
1113
+ return decoder.decode(decrypted);
1114
+ } catch {
1115
+ return null;
1036
1116
  }
1037
- return { fee: "0", symbol: this.getChainSymbol(chain) };
1038
1117
  }
1039
- /**
1040
- * Send a transaction
1041
- */
1042
- async sendTransaction(seed, chain, to, amount) {
1043
- await this.initialize();
1044
- try {
1045
- const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/send`, {
1046
- method: "POST",
1047
- headers: { "Content-Type": "application/json" },
1048
- body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
1049
- });
1050
- if (response.ok) {
1051
- const data = await response.json();
1052
- let txHash = data.txHash || data.transactionHash || data.hash;
1053
- if (txHash && typeof txHash === "object" && "hash" in txHash) {
1054
- txHash = txHash.hash;
1055
- }
1056
- if (chain === "ethereum" && txHash && (typeof txHash !== "string" || !txHash.startsWith("0x") || txHash.length !== 66)) {
1057
- console.warn(`Invalid Ethereum tx hash format: ${txHash} (length: ${txHash?.length}, expected: 66)`);
1058
- }
1059
- return {
1060
- success: data.success,
1061
- txHash,
1062
- from: data.from,
1063
- to: data.to,
1064
- amount: data.amount,
1065
- chain: data.chain,
1066
- network: data.network
1067
- };
1118
+ async removeItem(key) {
1119
+ localStorage.removeItem(`${this.storagePrefix}${key}`);
1120
+ }
1121
+ async hasItem(key) {
1122
+ return localStorage.getItem(`${this.storagePrefix}${key}`) !== null;
1123
+ }
1124
+ async clear() {
1125
+ const keysToRemove = [];
1126
+ for (let i = 0; i < localStorage.length; i++) {
1127
+ const key = localStorage.key(i);
1128
+ if (key?.startsWith(this.storagePrefix)) {
1129
+ keysToRemove.push(key);
1068
1130
  }
1069
- const errorData = await response.json().catch(() => ({}));
1070
- return {
1071
- success: false,
1072
- error: errorData.error || `HTTP ${response.status}`
1073
- };
1074
- } catch (error) {
1075
- return {
1076
- success: false,
1077
- error: error instanceof Error ? error.message : "Transaction failed"
1078
- };
1079
1131
  }
1132
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
1080
1133
  }
1081
- /**
1082
- * Get the network configuration
1083
- */
1084
- getNetwork() {
1085
- return this.config.network;
1086
- }
1087
- /**
1088
- * Get API URL
1089
- */
1090
- getApiUrl() {
1091
- return this.config.apiUrl;
1134
+ };
1135
+ var MemoryStorageAdapter = class {
1136
+ storage = /* @__PURE__ */ new Map();
1137
+ async setItem(key, value) {
1138
+ this.storage.set(key, value);
1092
1139
  }
1093
- // ==========================================
1094
- // Private Helper Methods
1095
- // ==========================================
1096
- getDerivationPath(chain) {
1097
- const paths = {
1098
- bitcoin: this.config.network === "testnet" ? "m/84'/1'/0'/0/0" : "m/84'/0'/0'/0/0",
1099
- ethereum: "m/44'/60'/0'/0/0",
1100
- ton: "m/44'/607'/0'/0'/0'",
1101
- tron: "m/44'/195'/0'/0/0",
1102
- solana: "m/44'/501'/0'/0'",
1103
- spark: "m/44'/998'/0'/0/0"
1104
- };
1105
- return paths[chain];
1140
+ async getItem(key) {
1141
+ return this.storage.get(key) || null;
1106
1142
  }
1107
- getChainSymbol(chain) {
1108
- const symbols = {
1109
- ethereum: "ETH",
1110
- bitcoin: "BTC",
1111
- ton: "TON",
1112
- tron: "TRX",
1113
- solana: "SOL",
1114
- spark: "SAT"
1115
- };
1116
- return symbols[chain];
1143
+ async removeItem(key) {
1144
+ this.storage.delete(key);
1117
1145
  }
1118
- /**
1119
- * Derive address using browser-compatible libraries
1120
- */
1121
- async deriveBrowserAddress(seed, chain) {
1122
- const path = this.getDerivationPath(chain);
1123
- try {
1124
- let address;
1125
- switch (chain) {
1126
- case "ethereum":
1127
- address = deriveEthereumAddress(seed);
1128
- break;
1129
- case "bitcoin":
1130
- address = deriveBitcoinAddress(seed, this.config.network);
1131
- break;
1132
- case "tron":
1133
- address = deriveTronAddress(seed);
1134
- break;
1135
- case "spark":
1136
- address = deriveSparkAddress(seed, this.config.network);
1137
- break;
1138
- case "solana":
1139
- address = await deriveSolanaAddress(seed);
1140
- break;
1141
- case "ton":
1142
- address = await deriveTonAddress(seed);
1143
- break;
1144
- default:
1145
- throw new Error(`Unsupported chain: ${chain}`);
1146
- }
1147
- return { chain, address, path };
1148
- } catch (error) {
1149
- console.error(`Browser derivation failed for ${chain}:`, error);
1150
- throw error;
1151
- }
1146
+ async hasItem(key) {
1147
+ return this.storage.has(key);
1152
1148
  }
1153
- /**
1154
- * Derive all addresses using browser-compatible libraries
1155
- */
1156
- async deriveAllBrowserAddresses(seed) {
1157
- return deriveAllAddresses(seed, this.config.network);
1149
+ async clear() {
1150
+ this.storage.clear();
1158
1151
  }
1159
1152
  };
1160
- var defaultService = null;
1161
- function getZubariWdkService(config) {
1162
- if (!defaultService || config && config.network !== defaultService.getNetwork()) {
1163
- defaultService = new ZubariWdkService(config);
1153
+ function createSecureStorage() {
1154
+ if (typeof global !== "undefined" && global.nativeModuleProxy !== void 0) {
1155
+ const Platform = global.Platform;
1156
+ if (Platform?.OS === "ios") {
1157
+ return new KeychainStorageAdapter();
1158
+ } else if (Platform?.OS === "android") {
1159
+ return new KeystoreStorageAdapter();
1160
+ }
1164
1161
  }
1165
- return defaultService;
1162
+ if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
1163
+ return new WebEncryptedStorageAdapter();
1164
+ }
1165
+ return new MemoryStorageAdapter();
1166
1166
  }
1167
1167
 
1168
1168
  // src/wallet/WalletManager.ts