@enclave-hq/wallet-sdk 1.2.4 → 1.2.7

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.
@@ -58,6 +58,7 @@ interface IWalletAdapter extends ISigner {
58
58
  signTypedData?(typedData: any): Promise<string>;
59
59
  switchChain?(chainId: number): Promise<void>;
60
60
  addChain?(chainConfig: AddChainParams): Promise<void>;
61
+ requestSwitchAccount?(targetAddress?: string): Promise<Account>;
61
62
  readContract?<T = any>(params: ContractReadParams): Promise<T>;
62
63
  writeContract?(params: ContractWriteParams): Promise<string>;
63
64
  estimateGas?(params: ContractWriteParams): Promise<bigint>;
@@ -225,6 +226,8 @@ declare class WalletManager extends TypedEventEmitter<WalletManagerEvents> {
225
226
  addChainIfNotExists?: boolean;
226
227
  chainConfig?: AddChainParams;
227
228
  }): Promise<Account>;
229
+ requestSwitchAccount(targetAddress?: string): Promise<Account>;
230
+ ensureAccount(targetAddress: string): Promise<Account>;
228
231
  readContract<T = any>(address: string, abi: any[], functionName: string, args?: any[], chainType?: ChainType): Promise<T>;
229
232
  writeContract(address: string, abi: any[], functionName: string, args?: any[], options?: {
230
233
  value?: string;
@@ -263,8 +266,9 @@ interface WalletContextValue {
263
266
  interface WalletProviderProps {
264
267
  children: ReactNode;
265
268
  walletManager?: WalletManager;
269
+ autoRestoreFromStorage?: boolean;
266
270
  }
267
- declare function WalletProvider({ children, walletManager: externalWalletManager }: WalletProviderProps): React.JSX.Element;
271
+ declare function WalletProvider({ children, walletManager: externalWalletManager, autoRestoreFromStorage, }: WalletProviderProps): React.JSX.Element;
268
272
  declare function useWallet(): WalletContextValue;
269
273
 
270
274
  interface UseAccountResult {
@@ -58,6 +58,7 @@ interface IWalletAdapter extends ISigner {
58
58
  signTypedData?(typedData: any): Promise<string>;
59
59
  switchChain?(chainId: number): Promise<void>;
60
60
  addChain?(chainConfig: AddChainParams): Promise<void>;
61
+ requestSwitchAccount?(targetAddress?: string): Promise<Account>;
61
62
  readContract?<T = any>(params: ContractReadParams): Promise<T>;
62
63
  writeContract?(params: ContractWriteParams): Promise<string>;
63
64
  estimateGas?(params: ContractWriteParams): Promise<bigint>;
@@ -225,6 +226,8 @@ declare class WalletManager extends TypedEventEmitter<WalletManagerEvents> {
225
226
  addChainIfNotExists?: boolean;
226
227
  chainConfig?: AddChainParams;
227
228
  }): Promise<Account>;
229
+ requestSwitchAccount(targetAddress?: string): Promise<Account>;
230
+ ensureAccount(targetAddress: string): Promise<Account>;
228
231
  readContract<T = any>(address: string, abi: any[], functionName: string, args?: any[], chainType?: ChainType): Promise<T>;
229
232
  writeContract(address: string, abi: any[], functionName: string, args?: any[], options?: {
230
233
  value?: string;
@@ -263,8 +266,9 @@ interface WalletContextValue {
263
266
  interface WalletProviderProps {
264
267
  children: ReactNode;
265
268
  walletManager?: WalletManager;
269
+ autoRestoreFromStorage?: boolean;
266
270
  }
267
- declare function WalletProvider({ children, walletManager: externalWalletManager }: WalletProviderProps): React.JSX.Element;
271
+ declare function WalletProvider({ children, walletManager: externalWalletManager, autoRestoreFromStorage, }: WalletProviderProps): React.JSX.Element;
268
272
  declare function useWallet(): WalletContextValue;
269
273
 
270
274
  interface UseAccountResult {
@@ -846,7 +846,12 @@ var CHAIN_INFO = {
846
846
  symbol: "ETH",
847
847
  decimals: 18
848
848
  },
849
- rpcUrls: ["https://eth.llamarpc.com"],
849
+ // 使用支持浏览器 CORS 的公共 RPC,避免 dapp 域名被跨域拦截(如 eth.llamarpc.com 无 CORS 头)
850
+ rpcUrls: [
851
+ "https://cloudflare-eth.com",
852
+ "https://rpc.ankr.com/eth",
853
+ "https://eth.llamarpc.com"
854
+ ],
850
855
  blockExplorerUrls: ["https://etherscan.io"]
851
856
  },
852
857
  // EVM Testnets
@@ -1245,6 +1250,56 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
1245
1250
  }]
1246
1251
  });
1247
1252
  }
1253
+ /**
1254
+ * 请求切换账户
1255
+ * 弹出 MetaMask 账户选择界面,让用户选择或切换到目标地址
1256
+ * @param targetAddress 目标地址(可选),如果提供,会在切换后验证是否匹配
1257
+ * @returns 切换后的账户信息
1258
+ */
1259
+ async requestSwitchAccount(targetAddress) {
1260
+ const provider = this.getBrowserProvider();
1261
+ if (!provider) {
1262
+ throw new Error("MetaMask provider not available");
1263
+ }
1264
+ try {
1265
+ await provider.request({
1266
+ method: "wallet_requestPermissions",
1267
+ params: [{ eth_accounts: {} }]
1268
+ });
1269
+ const accounts = await provider.request({
1270
+ method: "eth_accounts"
1271
+ });
1272
+ if (!accounts || accounts.length === 0) {
1273
+ throw new ConnectionRejectedError(this.type);
1274
+ }
1275
+ const address = formatEVMAddress(accounts[0]);
1276
+ if (targetAddress && address.toLowerCase() !== targetAddress.toLowerCase()) {
1277
+ throw new Error(`\u8BF7\u5728 MetaMask \u4E2D\u9009\u62E9\u5730\u5740 ${targetAddress.slice(0, 6)}...${targetAddress.slice(-4)}\uFF0C\u5F53\u524D\u9009\u62E9\u7684\u662F ${address.slice(0, 6)}...${address.slice(-4)}`);
1278
+ }
1279
+ const chainId = this.currentAccount?.chainId || 1;
1280
+ const account = {
1281
+ universalAddress: createUniversalAddress(chainId, address),
1282
+ nativeAddress: address,
1283
+ chainId,
1284
+ chainType: ChainType.EVM,
1285
+ isActive: true
1286
+ };
1287
+ this.setAccount(account);
1288
+ this.emitAccountChanged(account);
1289
+ const viemChain = this.getViemChain(chainId);
1290
+ this.walletClient = viem.createWalletClient({
1291
+ account: address,
1292
+ chain: viemChain,
1293
+ transport: viem.custom(provider)
1294
+ });
1295
+ return account;
1296
+ } catch (error) {
1297
+ if (error.code === 4001) {
1298
+ throw new ConnectionRejectedError(this.type);
1299
+ }
1300
+ throw error;
1301
+ }
1302
+ }
1248
1303
  /**
1249
1304
  * 读取合约
1250
1305
  */
@@ -1470,6 +1525,46 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
1470
1525
 
1471
1526
  // src/adapters/tron/tronlink.ts
1472
1527
  init_types();
1528
+ var TronApiRateLimiter = class {
1529
+ constructor(minIntervalMs = 600) {
1530
+ this.lastCallTime = 0;
1531
+ this.minInterval = minIntervalMs;
1532
+ }
1533
+ /**
1534
+ * 等待直到可以进行下一次 API 调用
1535
+ */
1536
+ async waitForNextCall() {
1537
+ const now = Date.now();
1538
+ const timeSinceLastCall = now - this.lastCallTime;
1539
+ if (timeSinceLastCall < this.minInterval) {
1540
+ const waitTime = this.minInterval - timeSinceLastCall;
1541
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
1542
+ }
1543
+ this.lastCallTime = Date.now();
1544
+ }
1545
+ };
1546
+ var tronApiRateLimiter = new TronApiRateLimiter(600);
1547
+ async function retryWithBackoff(fn, maxRetries = 3, initialDelay = 500) {
1548
+ let lastError;
1549
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
1550
+ try {
1551
+ return await fn();
1552
+ } catch (error) {
1553
+ lastError = error;
1554
+ const errorMsg = error?.message || String(error);
1555
+ const errorLower = errorMsg.toLowerCase();
1556
+ const isRateLimitError = error?.response?.status === 429 || error?.status === 429 || errorLower.includes("429") || errorLower.includes("rate limit") || errorLower.includes("too many requests") || error?.code === "ERR_BAD_REQUEST" && error?.response?.status === 429;
1557
+ if (isRateLimitError && attempt < maxRetries - 1) {
1558
+ const delay = initialDelay * Math.pow(2, attempt);
1559
+ console.warn(`[TronLink] \u9047\u5230\u901F\u7387\u9650\u5236 (429)\uFF0C\u7B49\u5F85 ${delay}ms \u540E\u91CD\u8BD5 (${attempt + 1}/${maxRetries})...`);
1560
+ await new Promise((resolve) => setTimeout(resolve, delay));
1561
+ continue;
1562
+ }
1563
+ throw error;
1564
+ }
1565
+ }
1566
+ throw lastError;
1567
+ }
1473
1568
  var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
1474
1569
  constructor() {
1475
1570
  super(...arguments);
@@ -1647,10 +1742,12 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
1647
1742
  /**
1648
1743
  * 读取合约
1649
1744
  * 参考 webserver 的实现,使用 TronWeb 合约实例的标准 call() 方法
1745
+ * 带 TronGrid 限流 + 429 重试
1650
1746
  */
1651
1747
  async readContract(params) {
1652
1748
  this.ensureConnected();
1653
- try {
1749
+ await tronApiRateLimiter.waitForNextCall();
1750
+ const doRead = async () => {
1654
1751
  const tronWeb = this.getTronWeb();
1655
1752
  if (!this.currentAccount) {
1656
1753
  throw new Error("No account connected");
@@ -1665,19 +1762,17 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
1665
1762
  return result;
1666
1763
  } catch (method1Error) {
1667
1764
  console.warn("\u26A0\uFE0F [\u65B9\u6CD51] TronWeb\u6807\u51C6\u65B9\u6CD5\u5931\u8D25\uFF0C\u5C1D\u8BD5\u65B9\u6CD52:", method1Error.message);
1668
- try {
1669
- const contract2 = await tronWeb.contract().at(params.address);
1670
- const method2 = contract2[params.functionName];
1671
- if (!method2 || typeof method2 !== "function") {
1672
- throw new Error(`Function ${params.functionName} not found in contract`);
1673
- }
1674
- const result = await method2(...params.args || []).call();
1675
- return result;
1676
- } catch (method2Error) {
1677
- console.error("\u26A0\uFE0F [\u65B9\u6CD52] \u4E5F\u5931\u8D25:", method2Error.message);
1678
- throw method1Error;
1765
+ const contract2 = await tronWeb.contract().at(params.address);
1766
+ const method2 = contract2[params.functionName];
1767
+ if (!method2 || typeof method2 !== "function") {
1768
+ throw new Error(`Function ${params.functionName} not found in contract`);
1679
1769
  }
1770
+ const result = await method2(...params.args || []).call();
1771
+ return result;
1680
1772
  }
1773
+ };
1774
+ try {
1775
+ return await retryWithBackoff(doRead, 3, 800);
1681
1776
  } catch (error) {
1682
1777
  console.error("Read contract error:", error);
1683
1778
  throw new Error(`Failed to read contract: ${error.message || "Unknown error"}`);
@@ -1688,6 +1783,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
1688
1783
  */
1689
1784
  async writeContract(params) {
1690
1785
  this.ensureConnected();
1786
+ await tronApiRateLimiter.waitForNextCall();
1691
1787
  try {
1692
1788
  const tronWeb = this.getTronWeb();
1693
1789
  console.log("[TronLink] writeContract params:", {
@@ -1713,29 +1809,171 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
1713
1809
  }
1714
1810
  console.log("[TronLink] Function ABI:", functionAbi);
1715
1811
  console.log("[TronLink] Calling with args:", params.args);
1812
+ const TRON_FEE_LIMIT = 1e8;
1716
1813
  const options = {
1717
- feeLimit: params.gas || 1e8,
1718
- // 默认 100 TRX 的能量限制
1814
+ feeLimit: TRON_FEE_LIMIT,
1815
+ // 固定为 100 TRX 的能量限制
1719
1816
  callValue: params.value || 0
1720
1817
  // 发送的 TRX 数量(单位:SUN)
1721
1818
  };
1722
- const parameter = functionAbi.inputs.map((input, index) => ({
1723
- type: input.type,
1724
- value: params.args[index]
1725
- }));
1726
- console.log("[TronLink] Transaction options:", options);
1727
- console.log("[TronLink] Parameters:", parameter);
1728
- const functionSelector = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
1729
- console.log("[TronLink] Function selector:", functionSelector);
1730
- console.log("[TronLink] Transaction options:", options);
1731
- console.log("[TronLink] Parameters:", parameter);
1732
- const tx = await tronWeb.transactionBuilder.triggerSmartContract(
1733
- params.address,
1734
- functionSelector,
1735
- options,
1736
- parameter,
1737
- this.currentAccount.nativeAddress
1738
- );
1819
+ const hasTupleArray = functionAbi.inputs.some((input) => input.type === "tuple[]");
1820
+ console.log("[TronLink] \u68C0\u67E5 tuple[] \u7C7B\u578B:", {
1821
+ hasTupleArray,
1822
+ inputs: functionAbi.inputs.map((i) => ({ name: i.name, type: i.type }))
1823
+ });
1824
+ let tx;
1825
+ if (hasTupleArray) {
1826
+ console.log("[TronLink] \u68C0\u6D4B\u5230 tuple[] \u53C2\u6570\uFF0C\u4F7F\u7528\u624B\u52A8\u7F16\u7801\u65B9\u5F0F");
1827
+ const processedArgs = params.args.map((argValue, index) => {
1828
+ const input = functionAbi.inputs[index];
1829
+ if (input.type === "address" && typeof argValue === "string") {
1830
+ if (argValue.startsWith("T") && argValue.length === 34) {
1831
+ const hexAddress = tronWeb.address.toHex(argValue);
1832
+ return hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
1833
+ }
1834
+ return argValue.startsWith("0x") ? argValue : `0x${argValue}`;
1835
+ }
1836
+ if (input.type === "tuple[]" && Array.isArray(argValue)) {
1837
+ return argValue.map((tupleItem) => {
1838
+ if (input.components && Array.isArray(input.components)) {
1839
+ const processedTuple = {};
1840
+ input.components.forEach((component) => {
1841
+ let value = tupleItem[component.name];
1842
+ if (component.type === "address" && typeof value === "string") {
1843
+ if (value.startsWith("T") && value.length === 34) {
1844
+ const hexAddress = tronWeb.address.toHex(value);
1845
+ value = hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
1846
+ } else if (!value.startsWith("0x")) {
1847
+ value = `0x${value}`;
1848
+ }
1849
+ }
1850
+ processedTuple[component.name] = value;
1851
+ });
1852
+ return processedTuple;
1853
+ }
1854
+ return tupleItem;
1855
+ });
1856
+ }
1857
+ if (input.type === "tuple" && typeof argValue === "object" && !Array.isArray(argValue)) {
1858
+ if (input.components && Array.isArray(input.components)) {
1859
+ const processedTuple = {};
1860
+ input.components.forEach((component) => {
1861
+ let value = argValue[component.name];
1862
+ if (component.type === "address" && typeof value === "string") {
1863
+ if (value.startsWith("T") && value.length === 34) {
1864
+ const hexAddress = tronWeb.address.toHex(value);
1865
+ value = hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
1866
+ } else if (!value.startsWith("0x")) {
1867
+ value = `0x${value}`;
1868
+ }
1869
+ }
1870
+ processedTuple[component.name] = value;
1871
+ });
1872
+ return processedTuple;
1873
+ }
1874
+ }
1875
+ return argValue;
1876
+ });
1877
+ console.log("[TronLink] \u5904\u7406\u540E\u7684\u53C2\u6570\uFF08\u7528\u4E8E viem \u7F16\u7801\uFF09:", processedArgs);
1878
+ const encodedData = viem.encodeFunctionData({
1879
+ abi: [functionAbi],
1880
+ functionName: params.functionName,
1881
+ args: processedArgs
1882
+ });
1883
+ console.log("[TronLink] \u7F16\u7801\u540E\u7684\u6570\u636E:", encodedData);
1884
+ const functionSelector = encodedData.slice(0, 10);
1885
+ const parameterData = encodedData.slice(10);
1886
+ console.log("[TronLink] \u51FD\u6570\u9009\u62E9\u5668:", functionSelector);
1887
+ console.log("[TronLink] \u53C2\u6570\u6570\u636E:", parameterData);
1888
+ const functionSignature = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
1889
+ const parameterHexClean = parameterData.startsWith("0x") ? parameterData.slice(2) : parameterData;
1890
+ console.log("[TronLink] \u4F7F\u7528 TronWeb triggerSmartContract (rawParameter)...", {
1891
+ contractAddress: params.address,
1892
+ functionSelector: functionSignature,
1893
+ encodedDataLength: parameterHexClean.length
1894
+ });
1895
+ tx = await retryWithBackoff(
1896
+ () => tronWeb.transactionBuilder.triggerSmartContract(
1897
+ params.address,
1898
+ // Base58 格式的合约地址
1899
+ functionSignature,
1900
+ // 函数签名(用于识别函数)
1901
+ {
1902
+ feeLimit: options.feeLimit,
1903
+ callValue: options.callValue,
1904
+ rawParameter: parameterHexClean
1905
+ // 使用 rawParameter 直接提供编码后的数据
1906
+ },
1907
+ [],
1908
+ // parameter 留空(因为使用 rawParameter)
1909
+ this.currentAccount.nativeAddress
1910
+ // Base58 格式的发送地址
1911
+ ),
1912
+ 3,
1913
+ // 最多重试 3 次
1914
+ 500
1915
+ // 初始延迟 500ms
1916
+ );
1917
+ console.log("[TronLink] \u4F7F\u7528 TronWeb API \u6784\u5EFA\u7684\u4EA4\u6613:", tx);
1918
+ } else {
1919
+ const parameter = functionAbi.inputs.map((input, index) => {
1920
+ const argValue = params.args[index];
1921
+ if (input.type === "tuple" && typeof argValue === "object" && !Array.isArray(argValue)) {
1922
+ if (input.components && Array.isArray(input.components)) {
1923
+ return {
1924
+ type: input.type,
1925
+ value: input.components.map((component) => ({
1926
+ type: component.type,
1927
+ value: argValue[component.name]
1928
+ }))
1929
+ };
1930
+ }
1931
+ }
1932
+ if (input.type === "address" && typeof argValue === "string") {
1933
+ if (argValue.startsWith("T") && argValue.length === 34) {
1934
+ return {
1935
+ type: input.type,
1936
+ value: argValue
1937
+ };
1938
+ }
1939
+ try {
1940
+ const base58Address = tronWeb.address.fromHex(argValue.startsWith("0x") ? argValue : `0x${argValue}`);
1941
+ return {
1942
+ type: input.type,
1943
+ value: base58Address
1944
+ };
1945
+ } catch (e) {
1946
+ return {
1947
+ type: input.type,
1948
+ value: argValue
1949
+ };
1950
+ }
1951
+ }
1952
+ return {
1953
+ type: input.type,
1954
+ value: argValue
1955
+ };
1956
+ });
1957
+ console.log("[TronLink] Transaction options:", options);
1958
+ console.log("[TronLink] Parameters:", parameter);
1959
+ const functionSelector = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
1960
+ console.log("[TronLink] Function selector:", functionSelector);
1961
+ console.log("[TronLink] Transaction options:", options);
1962
+ console.log("[TronLink] Parameters:", parameter);
1963
+ tx = await retryWithBackoff(
1964
+ () => tronWeb.transactionBuilder.triggerSmartContract(
1965
+ params.address,
1966
+ functionSelector,
1967
+ options,
1968
+ parameter,
1969
+ this.currentAccount.nativeAddress
1970
+ ),
1971
+ 3,
1972
+ // 最多重试 3 次
1973
+ 500
1974
+ // 初始延迟 500ms
1975
+ );
1976
+ }
1739
1977
  console.log("[TronLink] Transaction built:", tx);
1740
1978
  if (!tx || !tx.transaction) {
1741
1979
  throw new Error("Failed to build transaction");
@@ -1775,6 +2013,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
1775
2013
  const maxAttempts = 60;
1776
2014
  while (attempts < maxAttempts) {
1777
2015
  try {
2016
+ await tronApiRateLimiter.waitForNextCall();
1778
2017
  const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
1779
2018
  if (txInfo && txInfo.id) {
1780
2019
  const receipt = {
@@ -3192,6 +3431,12 @@ _WalletConnectAdapter.providerChains = null;
3192
3431
  _WalletConnectAdapter.isInitializing = false;
3193
3432
  _WalletConnectAdapter.initPromise = null;
3194
3433
  var WalletConnectAdapter = _WalletConnectAdapter;
3434
+
3435
+ // src/adapters/tron/wallet-connect.ts
3436
+ var wallet_connect_exports = {};
3437
+ __export(wallet_connect_exports, {
3438
+ WalletConnectTronAdapter: () => WalletConnectTronAdapter
3439
+ });
3195
3440
  init_types();
3196
3441
  var _WalletConnectTronAdapter = class _WalletConnectTronAdapter extends WalletAdapter {
3197
3442
  constructor(projectId) {
@@ -3884,6 +4129,11 @@ _WalletConnectTronAdapter.walletInstance = null;
3884
4129
  _WalletConnectTronAdapter.walletProjectId = null;
3885
4130
  var WalletConnectTronAdapter = _WalletConnectTronAdapter;
3886
4131
 
4132
+ // src/internal/walletconnect-tron-loader.esm.ts
4133
+ function loadWalletConnectTronModule() {
4134
+ return wallet_connect_exports;
4135
+ }
4136
+
3887
4137
  // src/adapters/deep-link/adapter.ts
3888
4138
  init_types();
3889
4139
  var _DeepLinkAdapter = class _DeepLinkAdapter extends WalletAdapter {
@@ -4190,10 +4440,10 @@ var AdapterRegistry = class {
4190
4440
  "walletconnect" /* WALLETCONNECT */,
4191
4441
  () => new WalletConnectAdapter(this.config.walletConnectProjectId)
4192
4442
  );
4193
- this.register(
4194
- "walletconnect-tron" /* WALLETCONNECT_TRON */,
4195
- () => new WalletConnectTronAdapter(this.config.walletConnectProjectId)
4196
- );
4443
+ this.register("walletconnect-tron" /* WALLETCONNECT_TRON */, () => {
4444
+ const { WalletConnectTronAdapter: WalletConnectTronAdapter2 } = loadWalletConnectTronModule();
4445
+ return new WalletConnectTronAdapter2(this.config.walletConnectProjectId);
4446
+ });
4197
4447
  }
4198
4448
  this.register("tronlink" /* TRONLINK */, () => new TronLinkAdapter());
4199
4449
  this.register(
@@ -4708,6 +4958,41 @@ var WalletManager = class extends TypedEventEmitter {
4708
4958
  throw error;
4709
4959
  }
4710
4960
  }
4961
+ /**
4962
+ * Request account switch (opens wallet account selector)
4963
+ * @param targetAddress Optional target address to verify after switching
4964
+ * @returns The new account after switching
4965
+ */
4966
+ async requestSwitchAccount(targetAddress) {
4967
+ if (!this.primaryWallet) {
4968
+ throw new WalletNotConnectedError();
4969
+ }
4970
+ if (!this.primaryWallet.requestSwitchAccount) {
4971
+ throw new Error(`Account switching not supported by ${this.primaryWallet.type}`);
4972
+ }
4973
+ const account = await this.primaryWallet.requestSwitchAccount(targetAddress);
4974
+ if (this.config.enableStorage) {
4975
+ this.saveToStorage();
4976
+ }
4977
+ return account;
4978
+ }
4979
+ /**
4980
+ * Ensure the current account matches the target address
4981
+ * If not matching, request account switch
4982
+ * @param targetAddress The address that should be active
4983
+ * @returns The account (either existing or after switch)
4984
+ */
4985
+ async ensureAccount(targetAddress) {
4986
+ const currentAccount = this.getPrimaryAccount();
4987
+ if (!currentAccount) {
4988
+ throw new WalletNotConnectedError();
4989
+ }
4990
+ if (currentAccount.nativeAddress.toLowerCase() === targetAddress.toLowerCase()) {
4991
+ return currentAccount;
4992
+ }
4993
+ console.log(`[WalletManager] Current account ${currentAccount.nativeAddress} doesn't match target ${targetAddress}, requesting switch...`);
4994
+ return this.requestSwitchAccount(targetAddress);
4995
+ }
4711
4996
  // ===== Contract Calls =====
4712
4997
  /**
4713
4998
  * Read contract
@@ -4917,13 +5202,13 @@ var WalletManager = class extends TypedEventEmitter {
4917
5202
  if (currentAddress === savedAddress.toLowerCase()) {
4918
5203
  console.debug("[WalletManager] Address matches, attempting connect (should be silent if already authorized)");
4919
5204
  try {
4920
- const account2 = await adapter.connect(data.primaryChainId);
5205
+ const account = await adapter.connect(data.primaryChainId);
4921
5206
  this.setPrimaryWallet(adapter);
4922
5207
  this.connectedWallets.set(adapter.chainType, adapter);
4923
5208
  this.setupAdapterListeners(adapter, true);
4924
- this.emit("accountChanged", account2);
5209
+ this.emit("accountChanged", account);
4925
5210
  console.debug("[WalletManager] Connect successful");
4926
- return account2;
5211
+ return account;
4927
5212
  } catch (connectError) {
4928
5213
  console.debug("[WalletManager] Connect failed (might be user rejection):", connectError?.message);
4929
5214
  return null;
@@ -4943,12 +5228,12 @@ var WalletManager = class extends TypedEventEmitter {
4943
5228
  try {
4944
5229
  const tronWeb = adapter.getTronWeb?.();
4945
5230
  if (tronWeb && tronWeb.defaultAddress?.base58) {
4946
- const account2 = await adapter.connect(data.primaryChainId);
5231
+ const account = await adapter.connect(data.primaryChainId);
4947
5232
  this.setPrimaryWallet(adapter);
4948
5233
  this.connectedWallets.set(adapter.chainType, adapter);
4949
5234
  this.setupAdapterListeners(adapter, true);
4950
- this.emit("accountChanged", account2);
4951
- return account2;
5235
+ this.emit("accountChanged", account);
5236
+ return account;
4952
5237
  }
4953
5238
  } catch (silentError) {
4954
5239
  console.debug("Silent TronLink connection failed:", silentError);
@@ -4959,14 +5244,14 @@ var WalletManager = class extends TypedEventEmitter {
4959
5244
  const wcAdapter = adapter;
4960
5245
  if (typeof wcAdapter.restoreSession === "function") {
4961
5246
  console.debug("[WalletManager] Attempting to restore WalletConnect Tron session...");
4962
- const account2 = await wcAdapter.restoreSession(data.primaryChainId);
4963
- if (account2) {
5247
+ const account = await wcAdapter.restoreSession(data.primaryChainId);
5248
+ if (account) {
4964
5249
  console.debug("[WalletManager] WalletConnect Tron session restored successfully");
4965
5250
  this.setPrimaryWallet(adapter);
4966
5251
  this.connectedWallets.set(adapter.chainType, adapter);
4967
5252
  this.setupAdapterListeners(adapter, true);
4968
- this.emit("accountChanged", account2);
4969
- return account2;
5253
+ this.emit("accountChanged", account);
5254
+ return account;
4970
5255
  } else {
4971
5256
  console.debug("[WalletManager] No valid WalletConnect Tron session found");
4972
5257
  return null;
@@ -4977,12 +5262,12 @@ var WalletManager = class extends TypedEventEmitter {
4977
5262
  return null;
4978
5263
  }
4979
5264
  }
4980
- const account = await adapter.connect(data.primaryChainId);
4981
- this.setPrimaryWallet(adapter);
4982
- this.connectedWallets.set(adapter.chainType, adapter);
4983
- this.setupAdapterListeners(adapter, true);
4984
- this.emit("accountChanged", account);
4985
- return account;
5265
+ console.debug(
5266
+ "[WalletManager] restoreFromStorage: no silent session; skipping interactive connect (type:",
5267
+ data.primaryWalletType,
5268
+ ")"
5269
+ );
5270
+ return null;
4986
5271
  } catch (error) {
4987
5272
  console.debug("Failed to restore wallet from storage:", error);
4988
5273
  return null;
@@ -5025,7 +5310,11 @@ var WalletManager = class extends TypedEventEmitter {
5025
5310
 
5026
5311
  // src/react/WalletContext.tsx
5027
5312
  var WalletContext = React2.createContext(null);
5028
- function WalletProvider({ children, walletManager: externalWalletManager }) {
5313
+ function WalletProvider({
5314
+ children,
5315
+ walletManager: externalWalletManager,
5316
+ autoRestoreFromStorage = true
5317
+ }) {
5029
5318
  const [walletManager] = React2.useState(() => externalWalletManager || new WalletManager());
5030
5319
  const [account, setAccount] = React2.useState(null);
5031
5320
  const [connectedWallets, setConnectedWallets] = React2.useState([]);
@@ -5062,6 +5351,10 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
5062
5351
  return walletManager.signTransaction(transaction);
5063
5352
  }, [walletManager]);
5064
5353
  React2.useEffect(() => {
5354
+ if (!autoRestoreFromStorage) {
5355
+ setIsRestoring(false);
5356
+ return;
5357
+ }
5065
5358
  const restoreConnection = async () => {
5066
5359
  try {
5067
5360
  const restoredAccount = await walletManager.restoreFromStorage();
@@ -5076,7 +5369,7 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
5076
5369
  }
5077
5370
  };
5078
5371
  restoreConnection();
5079
- }, [walletManager, updateConnectedWallets]);
5372
+ }, [walletManager, updateConnectedWallets, autoRestoreFromStorage]);
5080
5373
  React2.useEffect(() => {
5081
5374
  const handleAccountChanged = (newAccount) => {
5082
5375
  setAccount(newAccount);