@zubari/sdk 0.4.5 → 0.5.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 (35) hide show
  1. package/dist/{TransactionService-Djonkbp4.d.ts → TransactionService-BtWUjKt_.d.ts} +14 -2
  2. package/dist/{TransactionService-1Jt8ZRqO.d.mts → TransactionService-Lr_WS6iR.d.mts} +14 -2
  3. package/dist/{WalletManager-DfvFJ-mk.d.ts → WalletManager-DQQwVkoa.d.ts} +4 -0
  4. package/dist/{WalletManager-j0tgNIKi.d.mts → WalletManager-Sbpx4E1-.d.mts} +4 -0
  5. package/dist/{contracts-BahTuxZj.d.mts → contracts-B842YprC.d.mts} +2 -2
  6. package/dist/{contracts-D7rVmNJy.d.ts → contracts-s_CDIruh.d.ts} +2 -2
  7. package/dist/index.d.mts +3 -3
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +305 -23
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +306 -24
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/protocols/index.js +2 -2
  14. package/dist/protocols/index.js.map +1 -1
  15. package/dist/protocols/index.mjs +2 -2
  16. package/dist/protocols/index.mjs.map +1 -1
  17. package/dist/react/index.d.mts +2 -2
  18. package/dist/react/index.d.ts +2 -2
  19. package/dist/react/index.js +303 -21
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/react/index.mjs +304 -22
  22. package/dist/react/index.mjs.map +1 -1
  23. package/dist/services/index.d.mts +1 -1
  24. package/dist/services/index.d.ts +1 -1
  25. package/dist/services/index.js +132 -8
  26. package/dist/services/index.js.map +1 -1
  27. package/dist/services/index.mjs +132 -8
  28. package/dist/services/index.mjs.map +1 -1
  29. package/dist/wallet/index.d.mts +2 -2
  30. package/dist/wallet/index.d.ts +2 -2
  31. package/dist/wallet/index.js +303 -21
  32. package/dist/wallet/index.js.map +1 -1
  33. package/dist/wallet/index.mjs +304 -22
  34. package/dist/wallet/index.mjs.map +1 -1
  35. package/package.json +1 -1
@@ -6,7 +6,7 @@ import { HDKey } from '@scure/bip32';
6
6
  import { bech32, base58check } from '@scure/base';
7
7
  import { sha256 } from '@noble/hashes/sha256';
8
8
  import { ripemd160 } from '@noble/hashes/ripemd160';
9
- import { createPublicClient, http, formatEther } from 'viem';
9
+ import { createPublicClient, http, formatEther, getAddress } from 'viem';
10
10
  import { mainnet, sepolia } from 'viem/chains';
11
11
 
12
12
  // src/react/useWalletManager.ts
@@ -116,6 +116,38 @@ var TESTNET_NETWORKS = {
116
116
  name: "Solana Devnet",
117
117
  rpcUrl: "https://api.devnet.solana.com",
118
118
  explorerUrl: "https://solscan.io?cluster=devnet"
119
+ },
120
+ tron: {
121
+ name: "TRON Nile Testnet",
122
+ chainId: 3448148188,
123
+ rpcUrl: "https://nile.trongrid.io",
124
+ explorerUrl: "https://nile.tronscan.org"
125
+ },
126
+ ton: {
127
+ name: "TON Testnet",
128
+ rpcUrl: "https://testnet.toncenter.com/api/v2",
129
+ explorerUrl: "https://testnet.tonscan.org"
130
+ }
131
+ };
132
+ var USDT_ADDRESSES = {
133
+ ethereum: {
134
+ mainnet: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
135
+ testnet: "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06"
136
+ // Sepolia (Test Tether USD)
137
+ },
138
+ tron: {
139
+ mainnet: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
140
+ testnet: "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf"
141
+ // Nile testnet
142
+ },
143
+ solana: {
144
+ mainnet: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
145
+ testnet: ""
146
+ // No official USDT on devnet
147
+ },
148
+ ton: {
149
+ mainnet: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
150
+ testnet: "kQD0GKBM8ZbryVk2aESmzfU6b9b_8era_IkvBSELujFZPsyy"
119
151
  }
120
152
  };
121
153
  var DERIVATION_PATHS = {
@@ -473,6 +505,60 @@ function generateSeedPhrase() {
473
505
 
474
506
  // src/services/ZubariWdkService.ts
475
507
  var DEFAULT_API_URL2 = "https://ckgwifsxka.us-east-2.awsapprunner.com";
508
+ var CHAIN_ERROR_MESSAGES = {
509
+ ethereum: {
510
+ "insufficient funds": "INSUFFICIENT_FUNDS",
511
+ "nonce too low": "NONCE_TOO_LOW",
512
+ "gas too low": "GAS_TOO_LOW",
513
+ "replacement transaction underpriced": "GAS_TOO_LOW",
514
+ "transaction underpriced": "GAS_TOO_LOW",
515
+ "invalid address": "INVALID_ADDRESS"
516
+ },
517
+ bitcoin: {
518
+ "insufficient funds": "INSUFFICIENT_FUNDS",
519
+ "dust": "DUST_AMOUNT",
520
+ "mempool": "MEMPOOL_FULL",
521
+ "invalid address": "INVALID_ADDRESS"
522
+ },
523
+ solana: {
524
+ "insufficient funds": "INSUFFICIENT_FUNDS",
525
+ "invalid account": "INVALID_ADDRESS",
526
+ "blockhash not found": "NETWORK_ERROR"
527
+ },
528
+ ton: {
529
+ "insufficient funds": "INSUFFICIENT_FUNDS",
530
+ "invalid address": "INVALID_ADDRESS"
531
+ },
532
+ tron: {
533
+ "insufficient funds": "INSUFFICIENT_FUNDS",
534
+ "invalid address": "INVALID_ADDRESS",
535
+ "bandwidth": "GAS_TOO_LOW"
536
+ },
537
+ spark: {
538
+ "insufficient funds": "INSUFFICIENT_FUNDS",
539
+ "invoice expired": "TIMEOUT",
540
+ "no route": "NETWORK_ERROR"
541
+ }
542
+ };
543
+ function parseChainError(chain, errorMessage) {
544
+ const errorLower = errorMessage.toLowerCase();
545
+ const chainErrors = CHAIN_ERROR_MESSAGES[chain];
546
+ for (const [pattern, code] of Object.entries(chainErrors)) {
547
+ if (errorLower.includes(pattern)) {
548
+ return code;
549
+ }
550
+ }
551
+ if (errorLower.includes("timeout") || errorLower.includes("timed out")) {
552
+ return "TIMEOUT";
553
+ }
554
+ if (errorLower.includes("network") || errorLower.includes("connection")) {
555
+ return "NETWORK_ERROR";
556
+ }
557
+ if (errorLower.includes("rejected") || errorLower.includes("denied")) {
558
+ return "REJECTED";
559
+ }
560
+ return "UNKNOWN";
561
+ }
476
562
  function isBrowser() {
477
563
  return typeof window !== "undefined" && typeof window.document !== "undefined";
478
564
  }
@@ -747,47 +833,117 @@ var ZubariWdkService = class {
747
833
  return { fee: "0", symbol: this.getChainSymbol(chain) };
748
834
  }
749
835
  /**
750
- * Send a transaction
836
+ * Send a transaction on any supported chain
837
+ *
838
+ * @param seed - BIP-39 seed phrase
839
+ * @param chain - Target blockchain (ethereum, bitcoin, solana, ton, tron, spark)
840
+ * @param to - Recipient address
841
+ * @param amount - Amount to send (in native units: ETH, BTC, SOL, etc.)
842
+ * @returns Transaction result with hash on success, or error details on failure
751
843
  */
752
844
  async sendTransaction(seed, chain, to, amount) {
753
845
  await this.initialize();
846
+ const startTime = Date.now();
847
+ console.log(`[ZubariWdkService] Sending ${chain} transaction`, {
848
+ to: `${to.slice(0, 10)}...${to.slice(-6)}`,
849
+ amount,
850
+ network: this.config.network
851
+ });
754
852
  try {
755
853
  const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/send`, {
756
854
  method: "POST",
757
855
  headers: { "Content-Type": "application/json" },
758
856
  body: JSON.stringify({ seed, chain, to, amount, network: this.config.network })
759
857
  });
858
+ const elapsed = Date.now() - startTime;
760
859
  if (response.ok) {
761
860
  const data = await response.json();
762
861
  let txHash = data.txHash || data.transactionHash || data.hash;
763
862
  if (txHash && typeof txHash === "object" && "hash" in txHash) {
764
863
  txHash = txHash.hash;
765
864
  }
766
- if (chain === "ethereum" && txHash && (typeof txHash !== "string" || !txHash.startsWith("0x") || txHash.length !== 66)) {
767
- console.warn(`Invalid Ethereum tx hash format: ${txHash} (length: ${txHash?.length}, expected: 66)`);
865
+ if (txHash) {
866
+ const isValid = this.validateTxHash(chain, txHash);
867
+ if (!isValid) {
868
+ console.warn(`[ZubariWdkService] Invalid ${chain} tx hash format:`, txHash);
869
+ }
870
+ }
871
+ console.log(`[ZubariWdkService] ${chain} transaction ${data.success ? "SUCCESS" : "FAILED"}`, {
872
+ txHash: txHash ? `${txHash.slice(0, 16)}...` : "N/A",
873
+ elapsed: `${elapsed}ms`
874
+ });
875
+ if (!data.success) {
876
+ const errorCode2 = parseChainError(chain, data.error || "");
877
+ return {
878
+ success: false,
879
+ error: data.error,
880
+ errorCode: errorCode2,
881
+ chain
882
+ };
768
883
  }
769
884
  return {
770
- success: data.success,
885
+ success: true,
771
886
  txHash,
772
887
  from: data.from,
773
888
  to: data.to,
774
889
  amount: data.amount,
775
- chain: data.chain,
776
- network: data.network
890
+ chain: data.chain || chain,
891
+ network: data.network || this.config.network
777
892
  };
778
893
  }
779
894
  const errorData = await response.json().catch(() => ({}));
895
+ const errorMessage = errorData.error || `HTTP ${response.status}`;
896
+ const errorCode = parseChainError(chain, errorMessage);
897
+ console.error(`[ZubariWdkService] ${chain} transaction FAILED`, {
898
+ status: response.status,
899
+ error: errorMessage,
900
+ errorCode,
901
+ elapsed: `${elapsed}ms`
902
+ });
780
903
  return {
781
904
  success: false,
782
- error: errorData.error || `HTTP ${response.status}`
905
+ error: errorMessage,
906
+ errorCode,
907
+ chain
783
908
  };
784
909
  } catch (error) {
910
+ const elapsed = Date.now() - startTime;
911
+ const errorMessage = error instanceof Error ? error.message : "Transaction failed";
912
+ const errorCode = parseChainError(chain, errorMessage);
913
+ console.error(`[ZubariWdkService] ${chain} transaction ERROR`, {
914
+ error: errorMessage,
915
+ errorCode,
916
+ elapsed: `${elapsed}ms`
917
+ });
785
918
  return {
786
919
  success: false,
787
- error: error instanceof Error ? error.message : "Transaction failed"
920
+ error: errorMessage,
921
+ errorCode,
922
+ chain
788
923
  };
789
924
  }
790
925
  }
926
+ /**
927
+ * Validate transaction hash format for a specific chain
928
+ */
929
+ validateTxHash(chain, txHash) {
930
+ switch (chain) {
931
+ case "ethereum":
932
+ return /^0x[a-fA-F0-9]{64}$/.test(txHash);
933
+ case "bitcoin":
934
+ return /^[a-fA-F0-9]{64}$/.test(txHash);
935
+ case "solana":
936
+ return /^[1-9A-HJ-NP-Za-km-z]{80,90}$/.test(txHash);
937
+ case "ton":
938
+ return txHash.length >= 40;
939
+ case "tron":
940
+ return /^[a-fA-F0-9]{64}$/.test(txHash);
941
+ case "spark":
942
+ return txHash.length >= 32;
943
+ default:
944
+ return true;
945
+ }
946
+ }
791
947
  /**
792
948
  * Get the network configuration
793
949
  */
@@ -1273,6 +1429,19 @@ async function getPriceForChain(chain) {
1273
1429
  const prices = await fetchPrices();
1274
1430
  return prices[chain] || 0;
1275
1431
  }
1432
+ function tonFriendlyToRaw(addr) {
1433
+ if (addr.includes(":")) return addr;
1434
+ try {
1435
+ const b64 = addr.replace(/-/g, "+").replace(/_/g, "/");
1436
+ const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
1437
+ if (bytes.length !== 36) return addr;
1438
+ const workchain = bytes[1] === 255 ? -1 : bytes[1];
1439
+ const hash = Array.from(bytes.slice(2, 34)).map((b) => b.toString(16).padStart(2, "0")).join("");
1440
+ return `${workchain}:${hash}`;
1441
+ } catch {
1442
+ return addr;
1443
+ }
1444
+ }
1276
1445
  var STORAGE_KEYS = {
1277
1446
  ENCRYPTED_SEED: "encrypted_seed",
1278
1447
  ACTIVE_WALLET: "active_wallet",
@@ -1777,26 +1946,53 @@ var WalletManager = class _WalletManager {
1777
1946
  }
1778
1947
  const networkConfig = this.getChainConfig(chain);
1779
1948
  let balance = "0";
1949
+ const tokenBalances = {};
1780
1950
  if (chain === "ethereum") {
1781
1951
  const viemChain = this.config.network === "mainnet" ? mainnet : sepolia;
1782
- console.log(`[WalletManager] Fetching ${chain} balance for ${address} using RPC: ${this.config.rpcUrl}`);
1952
+ const isTestnet = this.config.network !== "mainnet";
1783
1953
  const client = createPublicClient({
1784
1954
  chain: viemChain,
1785
1955
  transport: http(this.config.rpcUrl, {
1786
1956
  timeout: 15e3,
1787
- // 15 second timeout
1788
1957
  retryCount: 2,
1789
1958
  retryDelay: 1e3
1790
1959
  })
1791
1960
  });
1792
- try {
1793
- const rawBalance = await client.getBalance({
1794
- address
1795
- });
1796
- balance = formatEther(rawBalance);
1797
- console.log(`[WalletManager] ${chain} balance fetched: ${balance} (raw: ${rawBalance})`);
1798
- } catch (error) {
1799
- console.error(`[WalletManager] Failed to fetch ${chain} balance from ${this.config.rpcUrl}:`, error);
1961
+ const usdtAddr = USDT_ADDRESSES.ethereum?.[isTestnet ? "testnet" : "mainnet"];
1962
+ const erc20BalanceOfAbi = [{
1963
+ type: "function",
1964
+ name: "balanceOf",
1965
+ stateMutability: "view",
1966
+ inputs: [{ name: "account", type: "address" }],
1967
+ outputs: [{ name: "", type: "uint256" }]
1968
+ }];
1969
+ const checksumAddr = getAddress(address);
1970
+ const [ethResult, usdtResult] = await Promise.allSettled([
1971
+ client.getBalance({ address: checksumAddr }),
1972
+ usdtAddr ? client.readContract({
1973
+ address: getAddress(usdtAddr),
1974
+ abi: erc20BalanceOfAbi,
1975
+ functionName: "balanceOf",
1976
+ args: [checksumAddr]
1977
+ }) : Promise.resolve(null)
1978
+ ]);
1979
+ if (ethResult.status === "fulfilled") {
1980
+ balance = formatEther(ethResult.value);
1981
+ } else {
1982
+ console.error(`[WalletManager] Failed to fetch ETH balance:`, ethResult.reason);
1983
+ }
1984
+ if (usdtResult.status === "fulfilled" && usdtResult.value != null) {
1985
+ try {
1986
+ const rawUsdt = BigInt(usdtResult.value);
1987
+ const usdtAmount = Number(rawUsdt) / 1e6;
1988
+ if (usdtAmount > 0) {
1989
+ tokenBalances.USDT = { balance: usdtAmount.toFixed(6), balanceUsd: usdtAmount };
1990
+ }
1991
+ } catch (err) {
1992
+ console.warn("[WalletManager] Failed to parse ETH USDT balance:", err);
1993
+ }
1994
+ } else if (usdtResult.status === "rejected") {
1995
+ console.warn("[WalletManager] Failed to fetch ETH USDT balance:", usdtResult.reason);
1800
1996
  }
1801
1997
  } else if (chain === "bitcoin") {
1802
1998
  const isMainnet = this.config.network === "mainnet" || address.startsWith("bc1") || address.startsWith("1") || address.startsWith("3");
@@ -1852,8 +2048,41 @@ var WalletManager = class _WalletManager {
1852
2048
  } catch (error) {
1853
2049
  console.warn(`Failed to fetch ${chain} balance:`, error);
1854
2050
  }
2051
+ const isTestnet = this.config.network !== "mainnet";
2052
+ const usdtMint = USDT_ADDRESSES.solana?.[isTestnet ? "testnet" : "mainnet"];
2053
+ if (usdtMint) {
2054
+ try {
2055
+ const tokenResponse = await fetch(rpcUrl, {
2056
+ method: "POST",
2057
+ headers: { "Content-Type": "application/json" },
2058
+ body: JSON.stringify({
2059
+ jsonrpc: "2.0",
2060
+ id: 2,
2061
+ method: "getTokenAccountsByOwner",
2062
+ params: [
2063
+ address,
2064
+ { mint: usdtMint },
2065
+ { encoding: "jsonParsed" }
2066
+ ]
2067
+ })
2068
+ });
2069
+ if (tokenResponse.ok) {
2070
+ const tokenData = await tokenResponse.json();
2071
+ const accounts = tokenData.result?.value;
2072
+ if (accounts && accounts.length > 0) {
2073
+ const uiAmount = accounts[0].account?.data?.parsed?.info?.tokenAmount?.uiAmount;
2074
+ if (uiAmount && uiAmount > 0) {
2075
+ tokenBalances.USDT = { balance: uiAmount.toFixed(6), balanceUsd: uiAmount };
2076
+ }
2077
+ }
2078
+ }
2079
+ } catch (error) {
2080
+ console.warn("Failed to fetch Solana USDT balance:", error);
2081
+ }
2082
+ }
1855
2083
  } else if (chain === "tron") {
1856
- const baseUrl = this.config.network === "mainnet" ? "https://api.trongrid.io" : "https://api.shasta.trongrid.io";
2084
+ const tronConfig = getNetworkConfig("tron", this.config.network !== "mainnet");
2085
+ const baseUrl = tronConfig.rpcUrl;
1857
2086
  try {
1858
2087
  const response = await fetch(`${baseUrl}/v1/accounts/${address}`, {
1859
2088
  headers: { "Accept": "application/json" }
@@ -1863,12 +2092,28 @@ var WalletManager = class _WalletManager {
1863
2092
  if (data.data?.[0]?.balance !== void 0) {
1864
2093
  balance = (data.data[0].balance / 1e6).toFixed(6);
1865
2094
  }
2095
+ const isTestnet = this.config.network !== "mainnet";
2096
+ const usdtAddr = USDT_ADDRESSES.tron?.[isTestnet ? "testnet" : "mainnet"];
2097
+ if (usdtAddr && data.data?.[0]?.trc20) {
2098
+ const trc20List = data.data[0].trc20;
2099
+ for (const tokenObj of trc20List) {
2100
+ if (tokenObj[usdtAddr]) {
2101
+ const rawUsdtBalance = BigInt(tokenObj[usdtAddr]);
2102
+ const usdtAmount = Number(rawUsdtBalance) / 1e6;
2103
+ if (usdtAmount > 0) {
2104
+ tokenBalances.USDT = { balance: usdtAmount.toFixed(6), balanceUsd: usdtAmount };
2105
+ }
2106
+ break;
2107
+ }
2108
+ }
2109
+ }
1866
2110
  }
1867
2111
  } catch (error) {
1868
2112
  console.warn(`Failed to fetch ${chain} balance:`, error);
1869
2113
  }
1870
2114
  } else if (chain === "ton") {
1871
- const baseUrl = this.config.network === "mainnet" ? "https://toncenter.com/api/v2" : "https://testnet.toncenter.com/api/v2";
2115
+ const isTestnet = this.config.network !== "mainnet";
2116
+ const baseUrl = isTestnet ? "https://testnet.toncenter.com/api/v2" : "https://toncenter.com/api/v2";
1872
2117
  try {
1873
2118
  const response = await fetch(`${baseUrl}/getAddressBalance?address=${address}`, {
1874
2119
  headers: { "Accept": "application/json" }
@@ -1884,6 +2129,42 @@ var WalletManager = class _WalletManager {
1884
2129
  } catch (error) {
1885
2130
  console.warn(`Failed to fetch ${chain} balance:`, error);
1886
2131
  }
2132
+ const usdtJetton = USDT_ADDRESSES.ton?.[isTestnet ? "testnet" : "mainnet"];
2133
+ if (usdtJetton) {
2134
+ const tonapiBaseUrl = isTestnet ? "https://testnet.tonapi.io/v2" : "https://tonapi.io/v2";
2135
+ try {
2136
+ const rawAddr = tonFriendlyToRaw(address);
2137
+ const jettonResponse = await fetch(
2138
+ `${tonapiBaseUrl}/accounts/${encodeURIComponent(rawAddr)}/jettons?currencies=usd`,
2139
+ { headers: { "Accept": "application/json" } }
2140
+ );
2141
+ if (jettonResponse.ok) {
2142
+ const jettonData = await jettonResponse.json();
2143
+ const balances = jettonData.balances;
2144
+ if (balances && balances.length > 0) {
2145
+ for (const jb of balances) {
2146
+ const jettonAddr = jb.jetton?.address;
2147
+ if (jettonAddr) {
2148
+ const usdtRaw = tonFriendlyToRaw(usdtJetton);
2149
+ if (jettonAddr.toLowerCase() === usdtRaw.toLowerCase()) {
2150
+ const rawBalance = jb.balance;
2151
+ if (rawBalance) {
2152
+ const decimals = jb.jetton?.decimals || 6;
2153
+ const usdtAmount = Number(BigInt(rawBalance)) / Math.pow(10, decimals);
2154
+ if (usdtAmount > 0) {
2155
+ tokenBalances.USDT = { balance: usdtAmount.toFixed(6), balanceUsd: usdtAmount };
2156
+ }
2157
+ }
2158
+ break;
2159
+ }
2160
+ }
2161
+ }
2162
+ }
2163
+ }
2164
+ } catch (error) {
2165
+ console.warn("Failed to fetch TON USDT jetton balance:", error);
2166
+ }
2167
+ }
1887
2168
  } else if (chain === "spark") {
1888
2169
  try {
1889
2170
  const response = await fetch(`${this.config.apiUrl}/api/wallets/wdk/balance`, {
@@ -1915,7 +2196,8 @@ var WalletManager = class _WalletManager {
1915
2196
  balance,
1916
2197
  balanceUsd,
1917
2198
  address,
1918
- decimals: networkConfig.nativeCurrency.decimals
2199
+ decimals: networkConfig.nativeCurrency.decimals,
2200
+ ...Object.keys(tokenBalances).length > 0 ? { tokenBalances } : {}
1919
2201
  };
1920
2202
  }
1921
2203
  /**