@0xsquid/react-hooks 8.4.1-beta-tempo.0 → 8.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/core/constants.d.ts +0 -3
  2. package/dist/core/queries/queries-keys.d.ts +1 -1
  3. package/dist/core/types/config.d.ts +1 -0
  4. package/dist/hooks/index.d.ts +2 -2
  5. package/dist/hooks/transaction/send/useEstimateSendTransactionGas.d.ts +2 -6
  6. package/dist/hooks/transaction/useAllTransactionsStatus.d.ts +1 -0
  7. package/dist/hooks/transaction/useEstimate.d.ts +11 -5
  8. package/dist/hooks/user/useUserParams.d.ts +4 -0
  9. package/dist/{index-CaI-xWCW.js → index-5cyMUZhY.js} +1205 -1349
  10. package/dist/index-5cyMUZhY.js.map +1 -0
  11. package/dist/{index-B4aeecpP.js → index-BGVXRZI6.js} +1208 -1351
  12. package/dist/index-BGVXRZI6.js.map +1 -0
  13. package/dist/{index.es-BXf9jwuI.js → index.es-BfdAGErV.js} +3 -3
  14. package/dist/{index.es-BXf9jwuI.js.map → index.es-BfdAGErV.js.map} +1 -1
  15. package/dist/{index.es-DAfqL2H0.js → index.es-CeHwkxPw.js} +3 -3
  16. package/dist/{index.es-DAfqL2H0.js.map → index.es-CeHwkxPw.js.map} +1 -1
  17. package/dist/index.esm.js +2 -2
  18. package/dist/index.js +3 -4
  19. package/dist/index.js.map +1 -1
  20. package/dist/{secretService-CIYxEkTN.js → secretService-BMYOBXhv.js} +3 -3
  21. package/dist/{secretService-CIYxEkTN.js.map → secretService-BMYOBXhv.js.map} +1 -1
  22. package/dist/{secretService-Cld4gYfG.js → secretService-D_d3CFdp.js} +3 -3
  23. package/dist/{secretService-Cld4gYfG.js.map → secretService-D_d3CFdp.js.map} +1 -1
  24. package/dist/services/internal/assetsService.d.ts +2 -2
  25. package/dist/services/internal/estimateService.d.ts +27 -13
  26. package/dist/services/internal/transactionService.d.ts +0 -7
  27. package/dist/{stellarService.client-COeQeah_.js → stellarService.client-CIkvwxPo.js} +3 -3
  28. package/dist/{stellarService.client-COeQeah_.js.map → stellarService.client-CIkvwxPo.js.map} +1 -1
  29. package/dist/{stellarService.client-ocLzRIB4.js → stellarService.client-DOrCdvCd.js} +3 -3
  30. package/dist/{stellarService.client-ocLzRIB4.js.map → stellarService.client-DOrCdvCd.js.map} +1 -1
  31. package/package.json +3 -3
  32. package/dist/hooks/tokens/useSourceChainGasToken.d.ts +0 -11
  33. package/dist/hooks/transaction/useTempoFeeCheck.d.ts +0 -11
  34. package/dist/index-B4aeecpP.js.map +0 -1
  35. package/dist/index-CaI-xWCW.js.map +0 -1
  36. package/dist/services/internal/tempoService.d.ts +0 -82
  37. package/dist/tests/networkGasToken.test.d.ts +0 -1
  38. package/dist/tests/tempoService.test.d.ts +0 -1
@@ -1,5 +1,5 @@
1
1
  import { ChainType, ActionType, SquidDataType, BridgeType, BridgeProvider, FeeType } from '@0xsquid/squid-types';
2
- import { zeroAddress as zeroAddress$1, parseUnits, formatUnits, isAddress, SwitchChainError, UserRejectedRequestError, erc20Abi, getAddress, defineChain, encodeFunctionData } from 'viem';
2
+ import { zeroAddress as zeroAddress$1, parseUnits, formatUnits, isAddress, SwitchChainError, UserRejectedRequestError, getAddress, defineChain, encodeFunctionData, erc20Abi } from 'viem';
3
3
  import React, { useMemo, useCallback, useState, useEffect, createContext, useContext, useRef } from 'react';
4
4
  import { useQuery, useMutation, useQueries, useQueryClient, QueryClient, QueryClientProvider } from '@tanstack/react-query';
5
5
  import { fromBech32 } from '@cosmjs/encoding';
@@ -15,20 +15,20 @@ import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-ba
15
15
  import { PublicKey, VersionedTransaction, Transaction, SystemProgram, Connection } from '@solana/web3.js';
16
16
  import { Networks, StrKey, nativeToScVal, Address, rpc, TransactionBuilder, BASE_FEE, Contract, TimeoutInfinite, scValToNative, Operation, Transaction as Transaction$1, xdr } from '@stellar/stellar-sdk';
17
17
  import { SUI_TESTNET_CHAIN, SUI_MAINNET_CHAIN } from '@mysten/wallet-standard';
18
- import { CloudflareProvider, JsonRpcProvider, ethers, Interface, BrowserProvider, JsonRpcSigner, Contract as Contract$1, isError } from 'ethers';
18
+ import { CloudflareProvider, BrowserProvider, JsonRpcSigner, JsonRpcProvider, ethers, Interface, Contract as Contract$1, isError } from 'ethers';
19
19
  import BigNumber$1, { BigNumber } from 'bignumber.js';
20
20
  import { countries } from 'countries-list';
21
21
  import getSymbolFromCurrency from 'currency-symbol-map';
22
22
  import Fuse from 'fuse.js';
23
23
  import { create } from 'zustand';
24
24
  import { persist } from 'zustand/middleware';
25
- import { useAccount, useConnectors, useConnect, useDisconnect, useSwitchChain, useBalance, useReadContract, createConfig, http, useWalletClient, usePublicClient, WagmiProvider } from 'wagmi';
25
+ import { useAccount, useConnectors, useConnect, useDisconnect, useSwitchChain, createConfig, http, useWalletClient, usePublicClient, useBalance, useReadContract, WagmiProvider } from 'wagmi';
26
26
  import SafeAppsSDK, { TransactionStatus as TransactionStatus$1 } from '@safe-global/safe-apps-sdk';
27
27
  import { getWallets } from '@wallet-standard/core';
28
28
  import { SlushWallet } from '@mysten/slush-wallet';
29
+ import { injected, safe, metaMask, coinbaseWallet, walletConnect } from 'wagmi/connectors';
29
30
  import { StargateClient, SigningStargateClient } from '@cosmjs/stargate';
30
31
  import { SuiClient } from '@mysten/sui/client';
31
- import { injected, safe, metaMask, coinbaseWallet, walletConnect } from 'wagmi/connectors';
32
32
  import { coin as coin$1 } from '@cosmjs/proto-signing';
33
33
  import { Transaction as Transaction$2 } from '@mysten/sui/transactions';
34
34
  import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate';
@@ -124,9 +124,6 @@ const CHAIN_IDS = {
124
124
  SONEIUM: "1868",
125
125
  PEAQ: "3338",
126
126
  HEDERA: "295",
127
- MANTRA: "5888",
128
- CITREA: "4114",
129
- TEMPO: "4217",
130
127
  // others
131
128
  BITCOIN: "bitcoin",
132
129
  SOLANA: "solana-mainnet-beta",
@@ -21119,17 +21116,9 @@ function isOnChainTxData(squidData) {
21119
21116
  return [
21120
21117
  SquidDataType.OnChainExecution,
21121
21118
  SquidDataType.DepositAddressWithSignature,
21119
+ SquidDataType.OnChainExecutionWithSignature,
21122
21120
  ].includes(squidData.type);
21123
21121
  }
21124
- /**
21125
- * Checks if a route is of type deposit-with-signature
21126
- *
21127
- * deposit-with-signature routes are on-chain routes
21128
- * that require a signature from the user to execute
21129
- */
21130
- function isDepositWithSignatureTxData(squidData) {
21131
- return squidData.type === SquidDataType.DepositAddressWithSignature;
21132
- }
21133
21122
  function getHistoryTransactionId(tx) {
21134
21123
  switch (tx.txType) {
21135
21124
  case HistoryTxType.SWAP:
@@ -22288,7 +22277,7 @@ const keys = () => ({
22288
22277
  // ============
22289
22278
  // Transactions
22290
22279
  // ============
22291
- transaction: (fromChainId, toChainId, toTokenAddress, fromTokenAddress, price, slippage, sourceUserAddress, degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChainType, preHook, postHook, overrideGasRefundAddress) => [
22280
+ transaction: (fromChainId, toChainId, toTokenAddress, fromTokenAddress, price, slippage, getGasOnDestination, sourceUserAddress, degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChainType, preHook, postHook, overrideGasRefundAddress) => [
22292
22281
  ...keys().transactions(),
22293
22282
  QueryKeys.Transaction,
22294
22283
  fromChainId,
@@ -22297,6 +22286,7 @@ const keys = () => ({
22297
22286
  fromTokenAddress,
22298
22287
  price,
22299
22288
  slippage,
22289
+ getGasOnDestination,
22300
22290
  sourceUserAddress,
22301
22291
  degenMode,
22302
22292
  destinationAddress,
@@ -22457,6 +22447,7 @@ const getConfigWithDefaults = (config) => {
22457
22447
  integratorId: get$2(config, "integratorId", defaultConfigValues.integratorId),
22458
22448
  slippage: get$2(config, "slippage", defaultConfigValues.slippage),
22459
22449
  collectFees: get$2(config, "collectFees", defaultConfigValues.collectFees),
22450
+ enableGetGasOnDestination: get$2(config, "enableGetGasOnDestination", defaultConfigValues.enableGetGasOnDestination),
22460
22451
  apiUrl: get$2(config, "apiUrl", defaultConfigValues.apiUrl),
22461
22452
  priceImpactWarnings: get$2(config, "priceImpactWarnings", defaultConfigValues.priceImpactWarnings),
22462
22453
  initialAssets: get$2(config, "initialAssets", defaultConfigValues.initialAssets),
@@ -22946,8 +22937,8 @@ const sortAllTokens = (tokenA, tokenB) => {
22946
22937
  return 0;
22947
22938
  };
22948
22939
  const findToken = (tokens, chainId, address) => tokens.find((t) => t.chainId === chainId && t.address === address);
22949
- const findNativeToken = (tokens, chain) => tokens.find((t) => t.symbol.toUpperCase() === chain.nativeCurrency.symbol.toUpperCase() &&
22950
- t.chainId == chain.chainId);
22940
+ const findNativeToken = (tokens, chain) => tokens.find((t) => t.symbol.toUpperCase() === chain?.nativeCurrency.symbol.toUpperCase() &&
22941
+ t.chainId == chain?.chainId);
22951
22942
  const normalizeIbcAddress = (address) => {
22952
22943
  if (!address.toLowerCase().startsWith("ibc/")) {
22953
22944
  return address;
@@ -23158,7 +23149,7 @@ const filterViewableTokens = (tokens, config, direction) => {
23158
23149
  };
23159
23150
  const getSecretNetworkBalances = async (chainData, cosmosAddress, squidTokens, keplrTypeWallet) => {
23160
23151
  const squidSecretTokens = squidTokens.filter((t) => t.chainId === CHAIN_IDS.SECRET);
23161
- const { fetchAllSecretBalances } = await import('./secretService-CIYxEkTN.js');
23152
+ const { fetchAllSecretBalances } = await import('./secretService-BMYOBXhv.js');
23162
23153
  return fetchAllSecretBalances(chainData, cosmosAddress, squidSecretTokens, keplrTypeWallet);
23163
23154
  };
23164
23155
  function getTokenAssetsKey(token) {
@@ -24849,7 +24840,7 @@ class OnrampService {
24849
24840
  });
24850
24841
  return data;
24851
24842
  }
24852
- async getConfiguration({ chains: _, tokens, }) {
24843
+ async getConfiguration({ chains, tokens, }) {
24853
24844
  const { data } = await axios.get(`${this.baseUrl}/config`);
24854
24845
  // Filter supportedCryptos to only include tokens that match our provided tokens
24855
24846
  const filteredCryptos = data.supportedCryptos.filter((supportedCrypto) => tokens.some((token) => token.address.toLowerCase() ===
@@ -26474,7 +26465,7 @@ function useStellarWallets() {
26474
26465
  try {
26475
26466
  const { allowAllModules: initializeAllModules } = await import('@creit.tech/stellar-wallets-kit');
26476
26467
  const { LedgerModule } = await import('@creit.tech/stellar-wallets-kit/modules/ledger.module');
26477
- const { formatStellarWallet } = await import('./stellarService.client-ocLzRIB4.js');
26468
+ const { formatStellarWallet } = await import('./stellarService.client-DOrCdvCd.js');
26478
26469
  const modules = [...initializeAllModules(), new LedgerModule()];
26479
26470
  const promises = modules.map(async (module) => {
26480
26471
  const isAvailable = await module.isAvailable();
@@ -27781,310 +27772,580 @@ function useTrackSearchEmpty({ searchQuery, resultsLength, context, debounceMs =
27781
27772
  }, [context, debounceMs, resultsLength, searchQuery]);
27782
27773
  }
27783
27774
 
27784
- class StellarRpcClient {
27785
- server;
27786
- constructor(rpcUrl) {
27787
- this.server = new rpc.Server(rpcUrl);
27775
+ var hrc20 = [
27776
+ {
27777
+ inputs: [
27778
+ ],
27779
+ name: "associate",
27780
+ outputs: [
27781
+ {
27782
+ internalType: "uint256",
27783
+ name: "responseCode",
27784
+ type: "uint256"
27785
+ }
27786
+ ],
27787
+ stateMutability: "nonpayable",
27788
+ type: "function"
27789
+ }
27790
+ ];
27791
+
27792
+ /**
27793
+ * Client for interacting with the Hedera Mirrornode API.
27794
+ *
27795
+ * @docs https://mainnet.mirrornode.hedera.com/api/v1/docs
27796
+ */
27797
+ class HederaApiClient {
27798
+ apiUrl;
27799
+ constructor(apiUrl) {
27800
+ this.apiUrl = apiUrl;
27788
27801
  }
27789
- /**
27790
- * Returns the balance of a Stellar Contract Token. This is different from an Issued Token.
27791
- *
27792
- * With Contract Tokens, we need to call the .balance method on the token contract
27793
- * and simulate the transaction to get the balance.
27794
- */
27795
- async getBalance(userAddress, tokenAddress, chainId) {
27796
- const account = await this.server.getAccount(userAddress);
27797
- const network = getStellarNetwork(chainId);
27798
- if (network == null) {
27799
- throw new Error(`No Stellar network found for chainId ${chainId}`);
27800
- }
27801
- const txBuilder = new TransactionBuilder(account, {
27802
- fee: (BigInt(BASE_FEE) * BigInt(2)).toString(),
27803
- networkPassphrase: network,
27804
- });
27805
- const contract = new Contract(tokenAddress);
27806
- const tx = txBuilder
27807
- .addOperation(contract.call("balance", new Address(userAddress).toScVal()))
27808
- .setTimeout(TimeoutInfinite)
27809
- .build();
27810
- const simulateTxResponse = await this.server.simulateTransaction(tx);
27811
- if ("error" in simulateTxResponse) {
27812
- const isNoBalanceError = simulateTxResponse.error.includes("trying to get non-existing value for contract instance");
27813
- // If the error message indicates that the user has no balance just return 0
27814
- // We don't want to spam with this error as it's pretty common
27815
- if (isNoBalanceError) {
27816
- return "0";
27817
- }
27818
- throw new Error(`Failed to fetch balance. RPC response: ${simulateTxResponse.error}`);
27802
+ async isTokenAssociated({ address, token, }) {
27803
+ const accountInfo = await this.getAccountInfo(address);
27804
+ // Unlimited auto associations
27805
+ if (accountInfo.max_automatic_token_associations === -1) {
27806
+ return true;
27819
27807
  }
27820
- if ("result" in simulateTxResponse && simulateTxResponse.result != null) {
27821
- const native = scValToNative(simulateTxResponse.result.retval);
27822
- return native.toString();
27808
+ // If there's no unlimited auto-associations, we need to check if the token is already associated.
27809
+ const { tokens: accountTokens } = await this.getAccountTokens(address);
27810
+ const tokenId = convertEvmAddressToHederaAccountId(token.address);
27811
+ if (accountTokens.some((t) => t.token_id === tokenId)) {
27812
+ // Token is already associated
27813
+ return true;
27823
27814
  }
27824
- throw new Error("Failed to fetch balance");
27825
- }
27826
- async getAllBalances(userAddress, tokens) {
27827
- const balancePromises = tokens.map((token) => {
27828
- return this.getBalance(userAddress, token.address, token.chainId);
27829
- });
27830
- const results = await Promise.allSettled(balancePromises);
27831
- const balances = results.map((result) => {
27832
- if (result.status === "fulfilled") {
27833
- return result.value;
27834
- }
27835
- return "0";
27836
- });
27837
- return balances.map((balance, index) => {
27838
- return {
27839
- ...tokens[index],
27840
- balance,
27841
- };
27842
- });
27815
+ // Finally, if not auto-associated, check if there is an available auto-association slot
27816
+ const autoAssociatedTokens = accountTokens.filter((t) => t.automatic_association);
27817
+ const remainingAutoAssociations = accountInfo.max_automatic_token_associations -
27818
+ autoAssociatedTokens.length;
27819
+ return remainingAutoAssociations > 0;
27843
27820
  }
27844
- /**
27845
- * Resolves when the transaction is confirmed, or fails after a timeout.
27846
- */
27847
- async waitForTransaction(txHash, { interval = 2_000, timeout = 40_000 } = {}) {
27848
- const startTime = Date.now();
27849
- while (true) {
27850
- const result = await this.server.getTransaction(txHash);
27851
- if (result.status === rpc.Api.GetTransactionStatus.NOT_FOUND) {
27852
- if (Date.now() - startTime > timeout) {
27853
- throw new Error(`Transaction ${txHash} not found within timeout`);
27854
- }
27855
- // eslint-disable-next-line @typescript-eslint/no-loop-func
27856
- await new Promise((res) => setTimeout(res, interval));
27857
- continue;
27858
- }
27859
- if (result.status === rpc.Api.GetTransactionStatus.SUCCESS) {
27860
- return result.status;
27861
- }
27862
- throw new Error(`Transaction failed with status: ${result.status}`);
27821
+ async getAccountInfo(address) {
27822
+ const data = await this.fetch(`accounts/${address}`);
27823
+ if (typeof data.max_automatic_token_associations !== "number") {
27824
+ throw new Error("Invalid max_automatic_token_associations type, expected number");
27863
27825
  }
27864
- }
27865
- async isAccountActivated(address) {
27866
- try {
27867
- await this.getAccount(address);
27868
- return true;
27826
+ if (typeof data.balance.balance !== "number") {
27827
+ throw new Error("Invalid balance type, expected number");
27869
27828
  }
27870
- catch (error) {
27871
- if (error?.message && error.message.includes("Account not found")) {
27872
- return false;
27873
- }
27874
- throw error;
27829
+ if (!Array.isArray(data.balance.tokens)) {
27830
+ throw new Error("Invalid tokens type, expected array");
27875
27831
  }
27832
+ return data;
27876
27833
  }
27877
- async getAccount(address) {
27878
- return this.server.getAccount(address);
27879
- }
27880
- async sendTransaction(transaction) {
27881
- const transactionResponse = await this.server.sendTransaction(transaction);
27882
- if (transactionResponse.status === "ERROR") {
27883
- throw new Error("Error sending transaction");
27834
+ async getAccountTokens(address) {
27835
+ const data = await this.fetch(`accounts/${address}/tokens`);
27836
+ if (!Array.isArray(data.tokens)) {
27837
+ throw new Error("Invalid tokens type, expected array");
27884
27838
  }
27885
- return transactionResponse;
27839
+ const firstToken = data.tokens[0];
27840
+ if (typeof firstToken?.automatic_association !== "boolean") {
27841
+ throw new Error("Invalid automatic_association type, expected boolean");
27842
+ }
27843
+ if (typeof firstToken?.token_id !== "string") {
27844
+ throw new Error("Invalid token_id type, expected string");
27845
+ }
27846
+ return data;
27886
27847
  }
27887
- async prepareTransaction(transaction) {
27888
- return this.server.prepareTransaction(transaction);
27848
+ async fetch(path) {
27849
+ const url = new URL(path, this.apiUrl);
27850
+ const response = await fetch(url);
27851
+ if (!response.ok) {
27852
+ throw new Error(`Hedera API error: ${response.status}`);
27853
+ }
27854
+ return response.json();
27889
27855
  }
27890
27856
  }
27891
27857
 
27892
- class XrplRpcClient {
27893
- rpcUrl;
27894
- constructor(rpcUrl) {
27895
- this.rpcUrl = rpcUrl;
27896
- }
27897
- async getBalance(address, tokenAddress) {
27898
- if (tokenAddress.toLowerCase() === nativeXrplTokenAddress.toLowerCase()) {
27899
- return this.getNativeBalance(address);
27900
- }
27901
- return this.getIssuedCurrencyBalance(address, tokenAddress);
27902
- }
27903
- async getAllBalances(address) {
27904
- const [nativeBalance, trustLineBalances] = await Promise.all([
27905
- this.getNativeBalance(address),
27906
- this.getTrustLines(address),
27907
- ]);
27908
- return [
27909
- {
27910
- balance: nativeBalance,
27911
- address: nativeXrplTokenAddress,
27912
- },
27913
- ...trustLineBalances.lines.map((line) => ({
27914
- balance: line.balance,
27915
- address: `${line.currency}.${line.account}`,
27916
- })),
27917
- ];
27918
- }
27919
- async getTrustLines(address, issuer) {
27920
- return this.call("account_lines", [
27921
- {
27922
- account: address,
27923
- ledger_index: "validated",
27924
- peer: issuer,
27925
- },
27926
- ]);
27927
- }
27928
- async getTrustLine(address, issuer, currency) {
27929
- const response = await this.getTrustLines(address, issuer);
27930
- const trustLine = response.lines.find((line) => line.currency === currency);
27931
- return trustLine ?? null;
27932
- }
27933
- async accountActivatedInfo(address) {
27934
- const serverState = await this.getServerState();
27935
- const reserveBaseBn = BigInt(serverState.state.validated_ledger.reserve_base);
27936
- try {
27937
- const accountInfo = await this.getAccountInfo(address);
27938
- const balanceBn = BigInt(accountInfo.account_data.Balance);
27939
- return {
27940
- isActivated: balanceBn >= reserveBaseBn,
27941
- reserveBaseBn,
27942
- };
27943
- }
27944
- catch (error) {
27945
- if (error.message?.includes("actNotFound")) {
27946
- return { isActivated: false, reserveBaseBn };
27858
+ hederaWalletConnect.type = "hederaWalletConnect";
27859
+ /**
27860
+ * Wagmi connector to interact with the Hedera EVM network via the WalletConnect protocol.
27861
+ *
27862
+ * The connector removes the need for a WalletConnect modal, and instead
27863
+ * communicates with the provided `extension` by opening the extension popup
27864
+ * for user interaction upon request.
27865
+ */
27866
+ function hederaWalletConnect(parameters) {
27867
+ const { extension, ...restParameters } = parameters;
27868
+ let provider_;
27869
+ let providerPromise;
27870
+ let connect;
27871
+ let displayUri;
27872
+ let sessionDelete;
27873
+ let disconnect;
27874
+ return createConnector((config) => ({
27875
+ id: `hedera-wc-${extension.id}`,
27876
+ name: extension.name,
27877
+ icon: extension.icon,
27878
+ type: hederaWalletConnect.type,
27879
+ async setup() {
27880
+ const provider = await this.getProvider().catch(() => null);
27881
+ if (!provider)
27882
+ return;
27883
+ if (!connect) {
27884
+ connect = this.onConnect.bind(this);
27885
+ provider.on("connect", connect);
27947
27886
  }
27948
- throw error;
27949
- }
27950
- }
27951
- /**
27952
- * Waits for a transaction to be validated and returns its final status.
27953
- * Resolves to 'success' or throws an error with the failed status.
27954
- */
27955
- async waitForTransaction(txHash, { interval = 2_000, timeout = 20_000 } = {}) {
27956
- const startTime = Date.now();
27957
- while (true) {
27887
+ if (!sessionDelete) {
27888
+ sessionDelete = this.onSessionDelete.bind(this);
27889
+ provider.on("session_delete", sessionDelete);
27890
+ }
27891
+ },
27892
+ async connect(params = {}) {
27958
27893
  try {
27959
- const response = await this.call("tx", [
27960
- {
27961
- transaction: txHash,
27962
- binary: false,
27963
- },
27964
- ]);
27965
- if (!response.validated) {
27966
- if (Date.now() - startTime > timeout) {
27967
- throw new Error(`Transaction ${txHash} not validated within timeout`);
27968
- }
27969
- // eslint-disable-next-line @typescript-eslint/no-loop-func
27970
- await new Promise((res) => setTimeout(res, interval));
27971
- continue;
27894
+ const provider = await this.getProvider();
27895
+ if (!provider)
27896
+ throw new ProviderNotFoundError();
27897
+ if (!displayUri) {
27898
+ displayUri = this.onDisplayUri;
27899
+ provider.on("display_uri", displayUri);
27972
27900
  }
27973
- const status = response.meta?.TransactionResult;
27974
- if (status === XrplTxStatus.SUCCESS) {
27975
- return status;
27901
+ if (!provider.session) {
27902
+ await provider.connect({
27903
+ ...("pairingTopic" in params
27904
+ ? { pairingTopic: params.pairingTopic }
27905
+ : {}),
27906
+ });
27976
27907
  }
27977
- else {
27978
- throw new Error(`Transaction failed with status: ${status}`);
27908
+ const accounts = (await provider.enable()).map((x) => getAddress(x));
27909
+ const currentChainId = await this.getChainId();
27910
+ if (displayUri) {
27911
+ provider.removeListener("display_uri", displayUri);
27912
+ displayUri = undefined;
27913
+ }
27914
+ if (connect) {
27915
+ provider.removeListener("connect", connect);
27916
+ connect = undefined;
27917
+ }
27918
+ if (!disconnect) {
27919
+ disconnect = this.onDisconnect.bind(this);
27920
+ provider.on("disconnect", disconnect);
27921
+ }
27922
+ if (!sessionDelete) {
27923
+ sessionDelete = this.onSessionDelete.bind(this);
27924
+ provider.on("session_delete", sessionDelete);
27979
27925
  }
27926
+ return { accounts, chainId: currentChainId };
27980
27927
  }
27981
27928
  catch (error) {
27982
- // txnNotFound = still pending or non-existent
27983
- if (error?.message?.includes("txnNotFound")) {
27984
- if (Date.now() - startTime > timeout) {
27985
- throw new Error(`Transaction ${txHash} not found within timeout`);
27986
- }
27987
- // eslint-disable-next-line @typescript-eslint/no-loop-func
27988
- await new Promise((res) => setTimeout(res, interval));
27989
- continue;
27929
+ if (/(user rejected|connection request reset)/i.test(error?.message)) {
27930
+ throw new UserRejectedRequestError(error);
27990
27931
  }
27991
27932
  throw error;
27992
27933
  }
27993
- }
27994
- }
27995
- async getServerState() {
27996
- return this.call("server_state", [{}]);
27934
+ },
27935
+ async disconnect() {
27936
+ const provider = await this.getProvider();
27937
+ try {
27938
+ await provider?.disconnect();
27939
+ }
27940
+ catch (error) {
27941
+ if (!/No matching key/i.test(error.message))
27942
+ throw error;
27943
+ }
27944
+ finally {
27945
+ if (disconnect) {
27946
+ provider?.removeListener("disconnect", disconnect);
27947
+ disconnect = undefined;
27948
+ }
27949
+ if (!connect) {
27950
+ connect = this.onConnect.bind(this);
27951
+ provider?.on("connect", connect);
27952
+ }
27953
+ if (sessionDelete) {
27954
+ provider?.removeListener("session_delete", sessionDelete);
27955
+ sessionDelete = undefined;
27956
+ }
27957
+ }
27958
+ },
27959
+ async getAccounts() {
27960
+ const provider = await this.getProvider();
27961
+ return provider.accounts.map((x) => getAddress(x));
27962
+ },
27963
+ async getProvider() {
27964
+ async function initProvider() {
27965
+ const optionalChains = config.chains.map((x) => x.id);
27966
+ if (!optionalChains.length)
27967
+ return;
27968
+ const { EthereumProvider } = await import('./index.es-BfdAGErV.js');
27969
+ const rawProvider = await EthereumProvider.init({
27970
+ ...restParameters,
27971
+ disableProviderPing: true,
27972
+ optionalChains,
27973
+ projectId: restParameters.projectId,
27974
+ rpcMap: Object.fromEntries(config.chains.map((chain) => {
27975
+ const [url] = extractRpcUrls({
27976
+ chain,
27977
+ transports: config.transports,
27978
+ });
27979
+ return [chain.id, url];
27980
+ })),
27981
+ showQrModal: false,
27982
+ // We need to specify a custom storage prefix to avoid conflicts with Wagmi's walletConnect instance
27983
+ // https://docs.reown.com/walletkit/web/usage#core-instance-sharing
27984
+ customStoragePrefix: "squid-hedera",
27985
+ });
27986
+ const proxiedProvider = new Proxy(rawProvider, {
27987
+ get(target, prop, receiver) {
27988
+ if (prop === "request") {
27989
+ return async (args) => {
27990
+ const signingMethods = [
27991
+ "eth_sendTransaction",
27992
+ "eth_signTransaction",
27993
+ ];
27994
+ if (signingMethods.includes(args.method)) {
27995
+ try {
27996
+ HederaExtensionHelper.extensionOpen(extension.id);
27997
+ }
27998
+ catch { }
27999
+ }
28000
+ // forward request to original provider
28001
+ return target.request(args);
28002
+ };
28003
+ }
28004
+ // forward all other properties/methods
28005
+ return Reflect.get(target, prop, receiver);
28006
+ },
28007
+ });
28008
+ return proxiedProvider;
28009
+ }
28010
+ if (!provider_) {
28011
+ if (!providerPromise)
28012
+ providerPromise = initProvider();
28013
+ provider_ = await providerPromise;
28014
+ provider_?.events.setMaxListeners(Number.POSITIVE_INFINITY);
28015
+ }
28016
+ return provider_;
28017
+ },
28018
+ async getChainId() {
28019
+ const provider = await this.getProvider();
28020
+ return provider.chainId;
28021
+ },
28022
+ async isAuthorized() {
28023
+ try {
28024
+ const accounts = await this.getAccounts();
28025
+ return accounts.length > 0;
28026
+ }
28027
+ catch {
28028
+ return false;
28029
+ }
28030
+ },
28031
+ onAccountsChanged(accounts) {
28032
+ if (accounts.length === 0)
28033
+ this.onDisconnect();
28034
+ else
28035
+ config.emitter.emit("change", {
28036
+ accounts: accounts.map((x) => getAddress(x)),
28037
+ });
28038
+ },
28039
+ onChainChanged(chain) {
28040
+ const chainId = Number(chain);
28041
+ config.emitter.emit("change", { chainId });
28042
+ },
28043
+ async onConnect(connectInfo) {
28044
+ const chainId = Number(connectInfo.chainId);
28045
+ const accounts = await this.getAccounts();
28046
+ config.emitter.emit("connect", { accounts, chainId });
28047
+ },
28048
+ async onDisconnect() {
28049
+ config.emitter.emit("disconnect");
28050
+ const provider = await this.getProvider();
28051
+ if (disconnect) {
28052
+ provider.removeListener("disconnect", disconnect);
28053
+ disconnect = undefined;
28054
+ }
28055
+ if (sessionDelete) {
28056
+ provider.removeListener("session_delete", sessionDelete);
28057
+ sessionDelete = undefined;
28058
+ }
28059
+ if (!connect) {
28060
+ connect = this.onConnect.bind(this);
28061
+ provider.on("connect", connect);
28062
+ }
28063
+ },
28064
+ onDisplayUri(uri) {
28065
+ config.emitter.emit("message", { type: "display_uri", data: uri });
28066
+ HederaExtensionHelper.extensionConnect(extension.id, uri);
28067
+ },
28068
+ onSessionDelete() {
28069
+ this.onDisconnect();
28070
+ },
28071
+ }));
28072
+ }
28073
+
28074
+ const createWagmiConfig = (squidChains, hederaExtensions) => {
28075
+ const filteredEvmChains = squidChains.filter((chain) => chain.chainType === ChainType.EVM);
28076
+ if (filteredEvmChains.length === 0) {
28077
+ throw new Error("At least one chain is required");
27997
28078
  }
27998
- async getAccountInfo(address) {
27999
- return this.call("account_info", [
28000
- {
28001
- account: address,
28002
- ledger_index: "validated",
28079
+ const wagmiChains = filteredEvmChains.map((chain) => {
28080
+ return defineChain({
28081
+ id: Number(chain.chainId),
28082
+ name: chain.networkName,
28083
+ nativeCurrency: {
28084
+ name: chain.nativeCurrency.name,
28085
+ symbol: chain.nativeCurrency.symbol,
28086
+ decimals: chain.nativeCurrency.decimals,
28003
28087
  },
28004
- ]);
28005
- }
28006
- /**
28007
- * Returns the balance of the user in the native XRP token
28008
- * formatted as a string
28009
- */
28010
- async getNativeBalance(address) {
28011
- const [accountInfo, serverState] = await Promise.all([
28012
- this.getAccountInfo(address),
28013
- this.getServerState(),
28014
- ]);
28015
- const balance = BigInt(accountInfo.account_data.Balance);
28016
- const ownerCount = BigInt(accountInfo.account_data.OwnerCount);
28017
- const reserveBase = BigInt(serverState.state.validated_ledger.reserve_base);
28018
- const reserveIncrement = BigInt(serverState.state.validated_ledger.reserve_inc);
28019
- const reserveBalance = reserveBase + ownerCount * reserveIncrement;
28020
- const spendableBalance = balance - reserveBalance;
28021
- return formatBNToReadable(spendableBalance, 6);
28022
- }
28023
- /**
28024
- * Returns the balance of the user in the given issued currency (e.g. RLUSD)
28025
- * formatted as a string
28026
- */
28027
- async getIssuedCurrencyBalance(address, tokenAddress) {
28028
- const response = await this.getTrustLines(address);
28029
- const tokenBalance = response.lines.find((line) => `${line.currency}.${line.account}` === tokenAddress);
28030
- return tokenBalance?.balance || "0";
28031
- }
28032
- async call(method, params) {
28033
- const response = await fetch(this.rpcUrl, {
28034
- method: "POST",
28035
- headers: {
28036
- "Content-Type": "application/json",
28088
+ rpcUrls: {
28089
+ public: {
28090
+ http: [chain.rpc],
28091
+ },
28092
+ default: {
28093
+ http: [chain.rpc],
28094
+ },
28037
28095
  },
28038
- body: JSON.stringify({
28039
- jsonrpc: "2.0",
28040
- id: 1,
28041
- method,
28042
- params,
28043
- }),
28044
28096
  });
28045
- const data = await response.json();
28046
- if (!data.result) {
28047
- throw new Error(`Invalid response from RPC (${method})`);
28048
- }
28049
- if ("error" in data.result) {
28050
- throw new Error(`Error from RPC (${method}): ${data.result.error}`);
28051
- }
28052
- return data.result;
28097
+ });
28098
+ const wcMetadata = {
28099
+ url: SQUID_METADATA.url,
28100
+ name: SQUID_METADATA.name,
28101
+ icons: [SQUID_METADATA.icon],
28102
+ description: SQUID_METADATA.description,
28103
+ };
28104
+ return createConfig({
28105
+ chains: wagmiChains,
28106
+ transports: Object.fromEntries(wagmiChains.map((chain) => [
28107
+ chain.id,
28108
+ http(chain.rpcUrls.public.http[0] ?? ""),
28109
+ ])),
28110
+ connectors: [
28111
+ injected(),
28112
+ safe({
28113
+ allowedDomains: [/app.safe.global$/],
28114
+ }),
28115
+ metaMask({
28116
+ dappMetadata: {
28117
+ name: SQUID_METADATA.name,
28118
+ url: SQUID_METADATA.url,
28119
+ iconUrl: SQUID_METADATA.icon,
28120
+ },
28121
+ }),
28122
+ coinbaseWallet({
28123
+ appName: SQUID_METADATA.name,
28124
+ appLogoUrl: SQUID_METADATA.icon,
28125
+ }),
28126
+ walletConnect({
28127
+ projectId: WALLETCONNECT_PROJECT_ID,
28128
+ metadata: wcMetadata,
28129
+ }),
28130
+ ...hederaExtensions.map((extension) => hederaWalletConnect({
28131
+ projectId: WALLETCONNECT_PROJECT_ID,
28132
+ metadata: wcMetadata,
28133
+ extension,
28134
+ })),
28135
+ ],
28136
+ });
28137
+ };
28138
+ // Taken from wagmi docs
28139
+ // https://wagmi.sh/react/guides/ethers
28140
+ function clientToSigner(client) {
28141
+ const { account, chain, transport } = client;
28142
+ if (!account || !chain || !transport) {
28143
+ return undefined;
28053
28144
  }
28145
+ const network = {
28146
+ chainId: chain.id,
28147
+ name: chain.name,
28148
+ ensAddress: chain.contracts?.ensRegistry?.address,
28149
+ };
28150
+ const provider = new BrowserProvider(transport, network);
28151
+ const signer = new JsonRpcSigner(provider, account.address);
28152
+ return signer;
28054
28153
  }
28055
28154
 
28056
- const clientCache = new Map();
28057
- async function getClient(chain) {
28058
- const key = `${chain.chainType}:${chain.chainId}`;
28059
- if (clientCache.has(key)) {
28060
- return clientCache.get(key);
28061
- }
28062
- const client = await createClient(chain);
28063
- clientCache.set(key, client);
28064
- return client;
28155
+ function useEvmSigner({ chainId }) {
28156
+ const { connector } = useAccount();
28157
+ const { data: client } = useWalletClient({ chainId, connector });
28158
+ const signer = useMemo(() => (client ? clientToSigner(client) : undefined), [client]);
28159
+ return { signer };
28065
28160
  }
28066
- async function createClient(chain) {
28067
- switch (chain.chainType) {
28068
- case ChainType.EVM:
28069
- return new JsonRpcProvider(chain.rpc);
28070
- case ChainType.COSMOS:
28071
- const rpcUrl = await getWorkingCosmosRpcUrl(chain);
28072
- return (await StargateClient.connect(rpcUrl));
28073
- case ChainType.SOLANA:
28074
- return new Connection(SOLANA_RPC_URL);
28075
- case ChainType.BTC:
28076
- return null;
28077
- case ChainType.SUI:
28078
- return new SuiClient({
28079
- url: chain.rpc,
28161
+ const useSigner = ({ chain }) => {
28162
+ const evmChainId = chain?.chainType === ChainType.EVM ? Number(chain.chainId) : undefined;
28163
+ // EVM and Cosmos need a different signer for each chain
28164
+ // This is not the case for Solana or Bitcoin as there's only one chain in those ecosystems
28165
+ const { signer: evmSigner } = useEvmSigner({ chainId: evmChainId });
28166
+ const { signer: cosmosSigner } = useCosmosSigner({ chain });
28167
+ const { signer: solanaSigner } = useSolanaContext();
28168
+ const { signer: bitcoinSigner } = useBitcoinContext();
28169
+ const { signer: suiSigner } = useSuiContext();
28170
+ const { signer: xrplSigner } = useXrplContext();
28171
+ const { signer: stellarSigner } = useStellarContext();
28172
+ const isEvmSignerReady = !!evmSigner;
28173
+ const isSolanaSignerReady = !!solanaSigner;
28174
+ const isCosmosSignerReady = !!cosmosSigner;
28175
+ const isBitcoinSignerReady = !!bitcoinSigner;
28176
+ const isSuiSignerReady = !!suiSigner;
28177
+ const isXrplSignerReady = !!xrplSigner;
28178
+ const isStellarSignerReady = !!stellarSigner;
28179
+ const isSignerReady = useMemo(() => {
28180
+ if (!chain?.chainType)
28181
+ return false;
28182
+ switch (chain.chainType) {
28183
+ case ChainType.EVM:
28184
+ return isEvmSignerReady;
28185
+ case ChainType.COSMOS:
28186
+ return isCosmosSignerReady;
28187
+ case ChainType.BTC:
28188
+ return isBitcoinSignerReady;
28189
+ case ChainType.SOLANA:
28190
+ return isSolanaSignerReady;
28191
+ case ChainType.SUI:
28192
+ return isSuiSignerReady;
28193
+ case ChainType.XRPL:
28194
+ return isXrplSignerReady;
28195
+ case ChainType.STELLAR:
28196
+ return isStellarSignerReady;
28197
+ }
28198
+ }, [
28199
+ chain?.chainType,
28200
+ isEvmSignerReady,
28201
+ isCosmosSignerReady,
28202
+ isBitcoinSignerReady,
28203
+ isSolanaSignerReady,
28204
+ isSuiSignerReady,
28205
+ isXrplSignerReady,
28206
+ isStellarSignerReady,
28207
+ ]);
28208
+ return {
28209
+ isSignerReady,
28210
+ evmSigner,
28211
+ cosmosSigner,
28212
+ bitcoinSigner,
28213
+ solanaSigner,
28214
+ suiSigner,
28215
+ xrplSigner,
28216
+ stellarSigner,
28217
+ };
28218
+ };
28219
+
28220
+ function useHederaTokenAssociations({ address, chain, token }) {
28221
+ const publicClient = usePublicClient({
28222
+ chainId: Number(CHAIN_IDS.HEDERA),
28223
+ });
28224
+ const { evmSigner } = useSigner({ chain });
28225
+ const queryClient = useQueryClient();
28226
+ /**
28227
+ * Creates a token association transaction where the destination account authorizes to receive the given token
28228
+ */
28229
+ const associateToken = useMutation({
28230
+ mutationFn: async () => {
28231
+ try {
28232
+ if (!evmSigner) {
28233
+ throw new Error("EVM signer not found");
28234
+ }
28235
+ if (chain?.chainId !== CHAIN_IDS.HEDERA ||
28236
+ token?.chainId !== CHAIN_IDS.HEDERA) {
28237
+ throw new Error("Chain and token to associate must be on Hedera");
28238
+ }
28239
+ const tokenAddress = parseEvmAddress(token.address);
28240
+ if (!tokenAddress) {
28241
+ throw new Error("Invalid token address");
28242
+ }
28243
+ const userAddress = parseEvmAddress(address);
28244
+ if (!userAddress) {
28245
+ throw new Error("Invalid user address");
28246
+ }
28247
+ const encodedData = encodeFunctionData({
28248
+ abi: hrc20,
28249
+ functionName: "associate",
28250
+ args: [],
28251
+ });
28252
+ const txRes = await evmSigner.sendTransaction({
28253
+ data: encodedData,
28254
+ to: tokenAddress,
28255
+ chainId: chain.chainId,
28256
+ });
28257
+ const receipt = await txRes.wait();
28258
+ if (receipt?.status !== 1) {
28259
+ throw new Error(`Transaction failed with status: ${receipt?.status}`);
28260
+ }
28261
+ return true;
28262
+ }
28263
+ catch (error) {
28264
+ console.error("Error associating Hedera token:", error);
28265
+ return false;
28266
+ }
28267
+ },
28268
+ async onSuccess() {
28269
+ queryClient.refetchQueries({
28270
+ queryKey: getPrefixKey(QueryKeys.IsHederaTokenAssociated),
28080
28271
  });
28081
- case ChainType.XRPL:
28082
- return new XrplRpcClient(chain.rpc);
28083
- case ChainType.STELLAR:
28084
- return new StellarRpcClient(chain.rpc);
28085
- }
28272
+ },
28273
+ });
28274
+ /**
28275
+ * Checks if the destination account has associated the given token.
28276
+ *
28277
+ * Hedera requires accounts to associate a token before being able to receive it.
28278
+ *
28279
+ * Accounts which have max. associations set to -1 can receive any token without previous association
28280
+ */
28281
+ const isTokenAssociated = useQuery({
28282
+ queryKey: keys().isHederaTokenAssociated(address, token?.chainId, token?.type, token?.address),
28283
+ queryFn: async () => {
28284
+ if (token?.chainId !== CHAIN_IDS.HEDERA) {
28285
+ return true;
28286
+ }
28287
+ // The native HBAR token doesn't need an association
28288
+ if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase()) {
28289
+ return true;
28290
+ }
28291
+ if (!chain || !address || !publicClient) {
28292
+ throw new Error("Missing required parameters");
28293
+ }
28294
+ // TODO: update types
28295
+ const apiUrl = chain?.chainConfig?.hedera?.mirrorNodeUrl;
28296
+ if (!apiUrl) {
28297
+ throw new Error("Missing Hedera mirror node URL in chain config");
28298
+ }
28299
+ const hederaApiClient = new HederaApiClient(apiUrl);
28300
+ return hederaApiClient.isTokenAssociated({
28301
+ address,
28302
+ token,
28303
+ });
28304
+ },
28305
+ enabled: !!address && !!publicClient && token?.chainId === CHAIN_IDS.HEDERA,
28306
+ });
28307
+ return {
28308
+ isTokenAssociated,
28309
+ associateToken,
28310
+ };
28086
28311
  }
28087
28312
 
28313
+ const useKeyboardNavigation = ({ onEscape }) => {
28314
+ const onKeyDown = useCallback((event) => {
28315
+ if (event.key === "Escape") {
28316
+ onEscape?.();
28317
+ return;
28318
+ }
28319
+ }, [onEscape]);
28320
+ useEffect(() => {
28321
+ document.addEventListener("keydown", onKeyDown, false);
28322
+ return () => {
28323
+ document.removeEventListener("keydown", onKeyDown, false);
28324
+ };
28325
+ }, [onKeyDown]);
28326
+ };
28327
+
28328
+ const useSquidQueryClient = () => {
28329
+ const queryClient = useQueryClient();
28330
+ const invalidateQueries = (key) => {
28331
+ const prefixKey = getPrefixKey(key);
28332
+ queryClient.invalidateQueries(prefixKey);
28333
+ };
28334
+ const refetchQueries = (key) => {
28335
+ const prefixKey = getPrefixKey(key);
28336
+ queryClient.refetchQueries(prefixKey);
28337
+ };
28338
+ const invalidateAndRefetchQueries = (key) => {
28339
+ invalidateQueries(key);
28340
+ refetchQueries(key);
28341
+ };
28342
+ return {
28343
+ invalidateQueries,
28344
+ refetchQueries,
28345
+ invalidateAndRefetchQueries,
28346
+ };
28347
+ };
28348
+
28088
28349
  /**
28089
28350
  * The default multicall3 address
28090
28351
  * available on most EVM chains
@@ -29099,6 +29360,372 @@ function timeout(ms, promise) {
29099
29360
  return Promise.race([promise, timeoutPromise]);
29100
29361
  }
29101
29362
 
29363
+ class StellarRpcClient {
29364
+ server;
29365
+ constructor(rpcUrl) {
29366
+ this.server = new rpc.Server(rpcUrl);
29367
+ }
29368
+ /**
29369
+ * Returns the balance of a Stellar Contract Token. This is different from an Issued Token.
29370
+ *
29371
+ * With Contract Tokens, we need to call the .balance method on the token contract
29372
+ * and simulate the transaction to get the balance.
29373
+ */
29374
+ async getBalance(userAddress, tokenAddress, chainId) {
29375
+ const account = await this.server.getAccount(userAddress);
29376
+ const network = getStellarNetwork(chainId);
29377
+ if (network == null) {
29378
+ throw new Error(`No Stellar network found for chainId ${chainId}`);
29379
+ }
29380
+ const txBuilder = new TransactionBuilder(account, {
29381
+ fee: (BigInt(BASE_FEE) * BigInt(2)).toString(),
29382
+ networkPassphrase: network,
29383
+ });
29384
+ const contract = new Contract(tokenAddress);
29385
+ const tx = txBuilder
29386
+ .addOperation(contract.call("balance", new Address(userAddress).toScVal()))
29387
+ .setTimeout(TimeoutInfinite)
29388
+ .build();
29389
+ const simulateTxResponse = await this.server.simulateTransaction(tx);
29390
+ if ("error" in simulateTxResponse) {
29391
+ const isNoBalanceError = simulateTxResponse.error.includes("trying to get non-existing value for contract instance");
29392
+ // If the error message indicates that the user has no balance just return 0
29393
+ // We don't want to spam with this error as it's pretty common
29394
+ if (isNoBalanceError) {
29395
+ return "0";
29396
+ }
29397
+ throw new Error(`Failed to fetch balance. RPC response: ${simulateTxResponse.error}`);
29398
+ }
29399
+ if ("result" in simulateTxResponse && simulateTxResponse.result != null) {
29400
+ const native = scValToNative(simulateTxResponse.result.retval);
29401
+ return native.toString();
29402
+ }
29403
+ throw new Error("Failed to fetch balance");
29404
+ }
29405
+ async getAllBalances(userAddress, tokens) {
29406
+ const balancePromises = tokens.map((token) => {
29407
+ return this.getBalance(userAddress, token.address, token.chainId);
29408
+ });
29409
+ const results = await Promise.allSettled(balancePromises);
29410
+ const balances = results.map((result) => {
29411
+ if (result.status === "fulfilled") {
29412
+ return result.value;
29413
+ }
29414
+ return "0";
29415
+ });
29416
+ return balances.map((balance, index) => {
29417
+ return {
29418
+ ...tokens[index],
29419
+ balance,
29420
+ };
29421
+ });
29422
+ }
29423
+ /**
29424
+ * Resolves when the transaction is confirmed, or fails after a timeout.
29425
+ */
29426
+ async waitForTransaction(txHash, { interval = 2_000, timeout = 40_000 } = {}) {
29427
+ const startTime = Date.now();
29428
+ while (true) {
29429
+ const result = await this.server.getTransaction(txHash);
29430
+ if (result.status === rpc.Api.GetTransactionStatus.NOT_FOUND) {
29431
+ if (Date.now() - startTime > timeout) {
29432
+ throw new Error(`Transaction ${txHash} not found within timeout`);
29433
+ }
29434
+ // eslint-disable-next-line @typescript-eslint/no-loop-func
29435
+ await new Promise((res) => setTimeout(res, interval));
29436
+ continue;
29437
+ }
29438
+ if (result.status === rpc.Api.GetTransactionStatus.SUCCESS) {
29439
+ return result.status;
29440
+ }
29441
+ throw new Error(`Transaction failed with status: ${result.status}`);
29442
+ }
29443
+ }
29444
+ async isAccountActivated(address) {
29445
+ try {
29446
+ await this.getAccount(address);
29447
+ return true;
29448
+ }
29449
+ catch (error) {
29450
+ if (error?.message && error.message.includes("Account not found")) {
29451
+ return false;
29452
+ }
29453
+ throw error;
29454
+ }
29455
+ }
29456
+ async getAccount(address) {
29457
+ return this.server.getAccount(address);
29458
+ }
29459
+ async sendTransaction(transaction) {
29460
+ const transactionResponse = await this.server.sendTransaction(transaction);
29461
+ if (transactionResponse.status === "ERROR") {
29462
+ throw new Error("Error sending transaction");
29463
+ }
29464
+ return transactionResponse;
29465
+ }
29466
+ async prepareTransaction(transaction) {
29467
+ return this.server.prepareTransaction(transaction);
29468
+ }
29469
+ }
29470
+
29471
+ class XrplRpcClient {
29472
+ rpcUrl;
29473
+ constructor(rpcUrl) {
29474
+ this.rpcUrl = rpcUrl;
29475
+ }
29476
+ async getBalance(address, tokenAddress) {
29477
+ if (tokenAddress.toLowerCase() === nativeXrplTokenAddress.toLowerCase()) {
29478
+ return this.getNativeBalance(address);
29479
+ }
29480
+ return this.getIssuedCurrencyBalance(address, tokenAddress);
29481
+ }
29482
+ async getAllBalances(address) {
29483
+ const [nativeBalance, trustLineBalances] = await Promise.all([
29484
+ this.getNativeBalance(address),
29485
+ this.getTrustLines(address),
29486
+ ]);
29487
+ return [
29488
+ {
29489
+ balance: nativeBalance,
29490
+ address: nativeXrplTokenAddress,
29491
+ },
29492
+ ...trustLineBalances.lines.map((line) => ({
29493
+ balance: line.balance,
29494
+ address: `${line.currency}.${line.account}`,
29495
+ })),
29496
+ ];
29497
+ }
29498
+ async getTrustLines(address, issuer) {
29499
+ return this.call("account_lines", [
29500
+ {
29501
+ account: address,
29502
+ ledger_index: "validated",
29503
+ peer: issuer,
29504
+ },
29505
+ ]);
29506
+ }
29507
+ async getTrustLine(address, issuer, currency) {
29508
+ const response = await this.getTrustLines(address, issuer);
29509
+ const trustLine = response.lines.find((line) => line.currency === currency);
29510
+ return trustLine ?? null;
29511
+ }
29512
+ async accountActivatedInfo(address) {
29513
+ const serverState = await this.getServerState();
29514
+ const reserveBaseBn = BigInt(serverState.state.validated_ledger.reserve_base);
29515
+ try {
29516
+ const accountInfo = await this.getAccountInfo(address);
29517
+ const balanceBn = BigInt(accountInfo.account_data.Balance);
29518
+ return {
29519
+ isActivated: balanceBn >= reserveBaseBn,
29520
+ reserveBaseBn,
29521
+ };
29522
+ }
29523
+ catch (error) {
29524
+ if (error.message?.includes("actNotFound")) {
29525
+ return { isActivated: false, reserveBaseBn };
29526
+ }
29527
+ throw error;
29528
+ }
29529
+ }
29530
+ /**
29531
+ * Waits for a transaction to be validated and returns its final status.
29532
+ * Resolves to 'success' or throws an error with the failed status.
29533
+ */
29534
+ async waitForTransaction(txHash, { interval = 2_000, timeout = 20_000 } = {}) {
29535
+ const startTime = Date.now();
29536
+ while (true) {
29537
+ try {
29538
+ const response = await this.call("tx", [
29539
+ {
29540
+ transaction: txHash,
29541
+ binary: false,
29542
+ },
29543
+ ]);
29544
+ if (!response.validated) {
29545
+ if (Date.now() - startTime > timeout) {
29546
+ throw new Error(`Transaction ${txHash} not validated within timeout`);
29547
+ }
29548
+ // eslint-disable-next-line @typescript-eslint/no-loop-func
29549
+ await new Promise((res) => setTimeout(res, interval));
29550
+ continue;
29551
+ }
29552
+ const status = response.meta?.TransactionResult;
29553
+ if (status === XrplTxStatus.SUCCESS) {
29554
+ return status;
29555
+ }
29556
+ else {
29557
+ throw new Error(`Transaction failed with status: ${status}`);
29558
+ }
29559
+ }
29560
+ catch (error) {
29561
+ // txnNotFound = still pending or non-existent
29562
+ if (error?.message?.includes("txnNotFound")) {
29563
+ if (Date.now() - startTime > timeout) {
29564
+ throw new Error(`Transaction ${txHash} not found within timeout`);
29565
+ }
29566
+ // eslint-disable-next-line @typescript-eslint/no-loop-func
29567
+ await new Promise((res) => setTimeout(res, interval));
29568
+ continue;
29569
+ }
29570
+ throw error;
29571
+ }
29572
+ }
29573
+ }
29574
+ async getServerState() {
29575
+ return this.call("server_state", [{}]);
29576
+ }
29577
+ async getAccountInfo(address) {
29578
+ return this.call("account_info", [
29579
+ {
29580
+ account: address,
29581
+ ledger_index: "validated",
29582
+ },
29583
+ ]);
29584
+ }
29585
+ /**
29586
+ * Returns the balance of the user in the native XRP token
29587
+ * formatted as a string
29588
+ */
29589
+ async getNativeBalance(address) {
29590
+ const [accountInfo, serverState] = await Promise.all([
29591
+ this.getAccountInfo(address),
29592
+ this.getServerState(),
29593
+ ]);
29594
+ const balance = BigInt(accountInfo.account_data.Balance);
29595
+ const ownerCount = BigInt(accountInfo.account_data.OwnerCount);
29596
+ const reserveBase = BigInt(serverState.state.validated_ledger.reserve_base);
29597
+ const reserveIncrement = BigInt(serverState.state.validated_ledger.reserve_inc);
29598
+ const reserveBalance = reserveBase + ownerCount * reserveIncrement;
29599
+ const spendableBalance = balance - reserveBalance;
29600
+ return formatBNToReadable(spendableBalance, 6);
29601
+ }
29602
+ /**
29603
+ * Returns the balance of the user in the given issued currency (e.g. RLUSD)
29604
+ * formatted as a string
29605
+ */
29606
+ async getIssuedCurrencyBalance(address, tokenAddress) {
29607
+ const response = await this.getTrustLines(address);
29608
+ const tokenBalance = response.lines.find((line) => `${line.currency}.${line.account}` === tokenAddress);
29609
+ return tokenBalance?.balance || "0";
29610
+ }
29611
+ async call(method, params) {
29612
+ const response = await fetch(this.rpcUrl, {
29613
+ method: "POST",
29614
+ headers: {
29615
+ "Content-Type": "application/json",
29616
+ },
29617
+ body: JSON.stringify({
29618
+ jsonrpc: "2.0",
29619
+ id: 1,
29620
+ method,
29621
+ params,
29622
+ }),
29623
+ });
29624
+ const data = await response.json();
29625
+ if (!data.result) {
29626
+ throw new Error(`Invalid response from RPC (${method})`);
29627
+ }
29628
+ if ("error" in data.result) {
29629
+ throw new Error(`Error from RPC (${method}): ${data.result.error}`);
29630
+ }
29631
+ return data.result;
29632
+ }
29633
+ }
29634
+
29635
+ const clientCache = new Map();
29636
+ async function getClient(chain) {
29637
+ const key = `${chain.chainType}:${chain.chainId}`;
29638
+ if (clientCache.has(key)) {
29639
+ return clientCache.get(key);
29640
+ }
29641
+ const client = await createClient(chain);
29642
+ clientCache.set(key, client);
29643
+ return client;
29644
+ }
29645
+ async function createClient(chain) {
29646
+ switch (chain.chainType) {
29647
+ case ChainType.EVM:
29648
+ return new JsonRpcProvider(chain.rpc);
29649
+ case ChainType.COSMOS:
29650
+ const rpcUrl = await getWorkingCosmosRpcUrl(chain);
29651
+ return (await StargateClient.connect(rpcUrl));
29652
+ case ChainType.SOLANA:
29653
+ return new Connection(SOLANA_RPC_URL);
29654
+ case ChainType.BTC:
29655
+ return null;
29656
+ case ChainType.SUI:
29657
+ return new SuiClient({
29658
+ url: chain.rpc,
29659
+ });
29660
+ case ChainType.XRPL:
29661
+ return new XrplRpcClient(chain.rpc);
29662
+ case ChainType.STELLAR:
29663
+ return new StellarRpcClient(chain.rpc);
29664
+ }
29665
+ }
29666
+
29667
+ class StellarApiClient {
29668
+ apiUrl;
29669
+ constructor(apiUrl) {
29670
+ this.apiUrl = apiUrl;
29671
+ }
29672
+ async getBaseReserve() {
29673
+ const response = await fetch(`${this.apiUrl}/ledgers?order=desc&limit=1`);
29674
+ if (!response.ok) {
29675
+ throw new Error(`Failed to fetch ledgers: ${response.status}`);
29676
+ }
29677
+ const ledgers = await response.json();
29678
+ const latestLedger = ledgers?._embedded.records?.[0];
29679
+ if (latestLedger?.base_reserve_in_stroops == null) {
29680
+ throw new Error("Invalid ledger data");
29681
+ }
29682
+ const baseReserveBn = BigInt(latestLedger.base_reserve_in_stroops);
29683
+ return baseReserveBn;
29684
+ }
29685
+ }
29686
+
29687
+ const DEFAULT_REFETCH_INTERVAL$1 = 20_000;
29688
+ function useStellarAccountActivation({ address, chain, token, }) {
29689
+ /**
29690
+ * Checks if the destination account exists on the Stellar network
29691
+ * Stellar accounts need to have a minimum balance before they can receive payments
29692
+ */
29693
+ const accountActivatedInfo = useQuery({
29694
+ queryKey: keys().stellarAccountActivatedInfo(address, chain?.chainId, chain?.chainType),
29695
+ queryFn: async () => {
29696
+ if (chain?.chainType !== ChainType.STELLAR ||
29697
+ token?.type !== ChainType.STELLAR) {
29698
+ return null;
29699
+ }
29700
+ if (!address) {
29701
+ throw new Error("Destination address is required");
29702
+ }
29703
+ // TODO: update types
29704
+ const [horizonApiUrl] = chain?.horizonRpcList;
29705
+ if (typeof horizonApiUrl !== "string") {
29706
+ throw new Error("Invalid Horizon API URL");
29707
+ }
29708
+ const stellarApiClient = new StellarApiClient(horizonApiUrl);
29709
+ const reserveBase = await stellarApiClient.getBaseReserve();
29710
+ // Stellar accounts require two base reserves to be activated
29711
+ // https://developers.stellar.org/docs/learn/fundamentals/lumens#minimum-balance
29712
+ const accountReserveBase = reserveBase * BigInt(2);
29713
+ const stellarRpcClient = await getClient(chain);
29714
+ const isActivated = await stellarRpcClient.isAccountActivated(address);
29715
+ return {
29716
+ isActivated,
29717
+ reserveBaseBn: accountReserveBase,
29718
+ };
29719
+ },
29720
+ enabled: !!address && chain?.chainType === ChainType.STELLAR,
29721
+ refetchInterval: DEFAULT_REFETCH_INTERVAL$1,
29722
+ refetchOnWindowFocus: true,
29723
+ });
29724
+ return {
29725
+ accountActivatedInfo,
29726
+ };
29727
+ }
29728
+
29102
29729
  const DEFAULT_REFRESH_INTERVAL_MS = 15000;
29103
29730
  const useEvmBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29104
29731
  const { isChainTypeConnected } = useWallet();
@@ -29293,8 +29920,6 @@ function useNativeTokenForChain(chain) {
29293
29920
  }
29294
29921
  };
29295
29922
  const nativeTokenForChainType = useMemo(() => {
29296
- if (!chain)
29297
- return undefined;
29298
29923
  return findNativeToken(getTokensForChainType(), chain);
29299
29924
  }, [chain]);
29300
29925
  return { nativeToken: nativeTokenForChainType };
@@ -29410,814 +30035,178 @@ const useSuiNativeBalance = ({ address, chain, }) => {
29410
30035
  token: nativeToken,
29411
30036
  userAddress: address,
29412
30037
  });
29413
- const balance = useMemo(() => {
29414
- if (nativeToken?.decimals && rawBalance) {
29415
- return {
29416
- decimals: nativeToken.decimals,
29417
- value: parseToBigInt(rawBalance, nativeToken.decimals),
29418
- };
29419
- }
29420
- }, [nativeToken?.decimals, rawBalance]);
29421
- return {
29422
- balance,
29423
- isLoading,
29424
- };
29425
- };
29426
- const useXrplNativeBalance = ({ address, chain, }) => {
29427
- const { nativeToken } = useNativeTokenForChain(chain);
29428
- const { balance: rawBalance, isLoading } = useXrplBalance({
29429
- chain,
29430
- token: nativeToken,
29431
- userAddress: address,
29432
- enabled: chain?.chainType === ChainType.XRPL,
29433
- });
29434
- const balance = useMemo(() => {
29435
- if (nativeToken?.decimals && rawBalance) {
29436
- return {
29437
- decimals: nativeToken.decimals,
29438
- value: parseToBigInt(rawBalance, nativeToken.decimals),
29439
- };
29440
- }
29441
- }, [nativeToken?.decimals, rawBalance]);
29442
- return {
29443
- balance,
29444
- isLoading,
29445
- };
29446
- };
29447
- const useStellarNativeBalance = ({ address, chain, }) => {
29448
- const { nativeToken } = useNativeTokenForChain(chain);
29449
- const { balance: rawBalance, isLoading } = useStellarBalance({
29450
- chain,
29451
- token: nativeToken,
29452
- userAddress: address,
29453
- enabled: chain?.chainType === ChainType.STELLAR,
29454
- });
29455
- const balance = useMemo(() => {
29456
- if (nativeToken?.decimals && rawBalance) {
29457
- return {
29458
- decimals: nativeToken.decimals,
29459
- value: parseToBigInt(rawBalance, nativeToken.decimals),
29460
- };
29461
- }
29462
- }, [nativeToken?.decimals, rawBalance]);
29463
- return {
29464
- balance,
29465
- isLoading,
29466
- };
29467
- };
29468
- const useNativeBalance = (chain) => {
29469
- const { connectedAddresses } = useWallet();
29470
- const { data: cosmosAddressForChain } = useCosmosForChain(chain);
29471
- // Cosmos is a special case because the address changes on every chain
29472
- // so we can't use the default cosmos connected address
29473
- const { balance: nativeCosmosBalance, isLoading: isCosmosLoading } = useCosmosNativeBalance({
29474
- address: cosmosAddressForChain,
29475
- chain,
29476
- });
29477
- const { balance: nativeEvmBalance, isLoading: isEvmLoading } = useEvmNativeBalance({ address: connectedAddresses[ChainType.EVM], chain });
29478
- const { balance: nativeBitcoinBalance, isLoading: isBitcoinLoading } = useBitcoinNativeBalance({
29479
- address: connectedAddresses[ChainType.BTC],
29480
- chain,
29481
- });
29482
- const { balance: nativeSolanaBalance, isLoading: isSolanaLoading } = useSolanaNativeBalance({
29483
- address: connectedAddresses[ChainType.SOLANA],
29484
- chain,
29485
- });
29486
- const { balance: nativeSuiBalance, isLoading: isSuiLoading } = useSuiNativeBalance({
29487
- address: connectedAddresses[ChainType.SUI],
29488
- chain,
29489
- });
29490
- const { balance: nativeXrplBalance, isLoading: isXrpLoading } = useXrplNativeBalance({
29491
- address: connectedAddresses[ChainType.XRPL],
29492
- chain,
29493
- });
29494
- const { balance: nativeStellarBalance, isLoading: isStellarLoading } = useStellarNativeBalance({
29495
- address: connectedAddresses[ChainType.STELLAR],
29496
- chain,
29497
- });
29498
- const { nativeBalance, nativeBalanceFormatted } = useMemo(() => {
29499
- let balance;
29500
- switch (chain?.chainType) {
29501
- case ChainType.EVM:
29502
- balance = nativeEvmBalance;
29503
- break;
29504
- case ChainType.COSMOS:
29505
- balance = nativeCosmosBalance;
29506
- break;
29507
- case ChainType.BTC:
29508
- balance = nativeBitcoinBalance;
29509
- break;
29510
- case ChainType.SOLANA:
29511
- balance = nativeSolanaBalance;
29512
- break;
29513
- case ChainType.SUI:
29514
- balance = nativeSuiBalance;
29515
- break;
29516
- case ChainType.XRPL:
29517
- balance = nativeXrplBalance;
29518
- break;
29519
- case ChainType.STELLAR:
29520
- balance = nativeStellarBalance;
29521
- }
29522
- const balanceFormatted = !!balance
29523
- ? formatBNToReadable(balance.value, balance.decimals)
29524
- : undefined;
29525
- return {
29526
- nativeBalance: balance,
29527
- nativeBalanceFormatted: balanceFormatted,
29528
- };
29529
- }, [
29530
- chain?.chainType,
29531
- nativeEvmBalance,
29532
- nativeCosmosBalance,
29533
- nativeBitcoinBalance,
29534
- nativeSolanaBalance,
29535
- nativeSuiBalance,
29536
- nativeXrplBalance,
29537
- nativeStellarBalance,
29538
- ]);
29539
- const isLoading = useMemo(() => {
29540
- if (!chain?.chainType)
29541
- return false;
29542
- switch (chain.chainType) {
29543
- case ChainType.EVM:
29544
- return isEvmLoading;
29545
- case ChainType.COSMOS:
29546
- return isCosmosLoading;
29547
- case ChainType.BTC:
29548
- return isBitcoinLoading;
29549
- case ChainType.SOLANA:
29550
- return isSolanaLoading;
29551
- case ChainType.SUI:
29552
- return isSuiLoading;
29553
- case ChainType.XRPL:
29554
- return isXrpLoading;
29555
- case ChainType.STELLAR:
29556
- return isStellarLoading;
29557
- }
29558
- }, [
29559
- chain?.chainType,
29560
- isEvmLoading,
29561
- isCosmosLoading,
29562
- isBitcoinLoading,
29563
- isSolanaLoading,
29564
- isSuiLoading,
29565
- isXrpLoading,
29566
- isStellarLoading,
29567
- ]);
29568
- return { nativeBalance, nativeBalanceFormatted, isLoading };
29569
- };
29570
-
29571
- function useHederaAccountActivation({ address, chain, token }) {
29572
- const { balance: destNativeEvmBalance } = useEvmNativeBalance({
29573
- chain,
29574
- address,
29575
- });
29576
- const isHederaAccountActivated = useMemo(() => {
29577
- if (token?.chainId !== CHAIN_IDS.HEDERA)
29578
- return true;
29579
- if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase())
29580
- return true;
29581
- return (!!destNativeEvmBalance?.value && destNativeEvmBalance.value > BigInt(0));
29582
- }, [token?.chainId, token?.address, destNativeEvmBalance?.value]);
29583
- return {
29584
- isHederaAccountActivated,
29585
- };
29586
- }
29587
-
29588
- var hrc20 = [
29589
- {
29590
- inputs: [
29591
- ],
29592
- name: "associate",
29593
- outputs: [
29594
- {
29595
- internalType: "uint256",
29596
- name: "responseCode",
29597
- type: "uint256"
29598
- }
29599
- ],
29600
- stateMutability: "nonpayable",
29601
- type: "function"
29602
- }
29603
- ];
29604
-
29605
- /**
29606
- * Client for interacting with the Hedera Mirrornode API.
29607
- *
29608
- * @docs https://mainnet.mirrornode.hedera.com/api/v1/docs
29609
- */
29610
- class HederaApiClient {
29611
- apiUrl;
29612
- constructor(apiUrl) {
29613
- this.apiUrl = apiUrl;
29614
- }
29615
- async isTokenAssociated({ address, token, }) {
29616
- const accountInfo = await this.getAccountInfo(address);
29617
- // Unlimited auto associations
29618
- if (accountInfo.max_automatic_token_associations === -1) {
29619
- return true;
29620
- }
29621
- // If there's no unlimited auto-associations, we need to check if the token is already associated.
29622
- const { tokens: accountTokens } = await this.getAccountTokens(address);
29623
- const tokenId = convertEvmAddressToHederaAccountId(token.address);
29624
- if (accountTokens.some((t) => t.token_id === tokenId)) {
29625
- // Token is already associated
29626
- return true;
29627
- }
29628
- // Finally, if not auto-associated, check if there is an available auto-association slot
29629
- const autoAssociatedTokens = accountTokens.filter((t) => t.automatic_association);
29630
- const remainingAutoAssociations = accountInfo.max_automatic_token_associations -
29631
- autoAssociatedTokens.length;
29632
- return remainingAutoAssociations > 0;
29633
- }
29634
- async getAccountInfo(address) {
29635
- const data = await this.fetch(`accounts/${address}`);
29636
- if (typeof data.max_automatic_token_associations !== "number") {
29637
- throw new Error("Invalid max_automatic_token_associations type, expected number");
29638
- }
29639
- if (typeof data.balance.balance !== "number") {
29640
- throw new Error("Invalid balance type, expected number");
29641
- }
29642
- if (!Array.isArray(data.balance.tokens)) {
29643
- throw new Error("Invalid tokens type, expected array");
29644
- }
29645
- return data;
29646
- }
29647
- async getAccountTokens(address) {
29648
- const data = await this.fetch(`accounts/${address}/tokens`);
29649
- if (!Array.isArray(data.tokens)) {
29650
- throw new Error("Invalid tokens type, expected array");
29651
- }
29652
- const firstToken = data.tokens[0];
29653
- if (typeof firstToken?.automatic_association !== "boolean") {
29654
- throw new Error("Invalid automatic_association type, expected boolean");
29655
- }
29656
- if (typeof firstToken?.token_id !== "string") {
29657
- throw new Error("Invalid token_id type, expected string");
29658
- }
29659
- return data;
29660
- }
29661
- async fetch(path) {
29662
- const url = new URL(path, this.apiUrl);
29663
- const response = await fetch(url);
29664
- if (!response.ok) {
29665
- throw new Error(`Hedera API error: ${response.status}`);
29666
- }
29667
- return response.json();
29668
- }
29669
- }
29670
-
29671
- hederaWalletConnect.type = "hederaWalletConnect";
29672
- /**
29673
- * Wagmi connector to interact with the Hedera EVM network via the WalletConnect protocol.
29674
- *
29675
- * The connector removes the need for a WalletConnect modal, and instead
29676
- * communicates with the provided `extension` by opening the extension popup
29677
- * for user interaction upon request.
29678
- */
29679
- function hederaWalletConnect(parameters) {
29680
- const { extension, ...restParameters } = parameters;
29681
- let provider_;
29682
- let providerPromise;
29683
- let connect;
29684
- let displayUri;
29685
- let sessionDelete;
29686
- let disconnect;
29687
- return createConnector((config) => ({
29688
- id: `hedera-wc-${extension.id}`,
29689
- name: extension.name,
29690
- icon: extension.icon,
29691
- type: hederaWalletConnect.type,
29692
- async setup() {
29693
- const provider = await this.getProvider().catch(() => null);
29694
- if (!provider)
29695
- return;
29696
- if (!connect) {
29697
- connect = this.onConnect.bind(this);
29698
- provider.on("connect", connect);
29699
- }
29700
- if (!sessionDelete) {
29701
- sessionDelete = this.onSessionDelete.bind(this);
29702
- provider.on("session_delete", sessionDelete);
29703
- }
29704
- },
29705
- async connect(params = {}) {
29706
- try {
29707
- const provider = await this.getProvider();
29708
- if (!provider)
29709
- throw new ProviderNotFoundError();
29710
- if (!displayUri) {
29711
- displayUri = this.onDisplayUri;
29712
- provider.on("display_uri", displayUri);
29713
- }
29714
- if (!provider.session) {
29715
- await provider.connect({
29716
- ...("pairingTopic" in params
29717
- ? { pairingTopic: params.pairingTopic }
29718
- : {}),
29719
- });
29720
- }
29721
- const accounts = (await provider.enable()).map((x) => getAddress(x));
29722
- const currentChainId = await this.getChainId();
29723
- if (displayUri) {
29724
- provider.removeListener("display_uri", displayUri);
29725
- displayUri = undefined;
29726
- }
29727
- if (connect) {
29728
- provider.removeListener("connect", connect);
29729
- connect = undefined;
29730
- }
29731
- if (!disconnect) {
29732
- disconnect = this.onDisconnect.bind(this);
29733
- provider.on("disconnect", disconnect);
29734
- }
29735
- if (!sessionDelete) {
29736
- sessionDelete = this.onSessionDelete.bind(this);
29737
- provider.on("session_delete", sessionDelete);
29738
- }
29739
- return { accounts, chainId: currentChainId };
29740
- }
29741
- catch (error) {
29742
- if (/(user rejected|connection request reset)/i.test(error?.message)) {
29743
- throw new UserRejectedRequestError(error);
29744
- }
29745
- throw error;
29746
- }
29747
- },
29748
- async disconnect() {
29749
- const provider = await this.getProvider();
29750
- try {
29751
- await provider?.disconnect();
29752
- }
29753
- catch (error) {
29754
- if (!/No matching key/i.test(error.message))
29755
- throw error;
29756
- }
29757
- finally {
29758
- if (disconnect) {
29759
- provider?.removeListener("disconnect", disconnect);
29760
- disconnect = undefined;
29761
- }
29762
- if (!connect) {
29763
- connect = this.onConnect.bind(this);
29764
- provider?.on("connect", connect);
29765
- }
29766
- if (sessionDelete) {
29767
- provider?.removeListener("session_delete", sessionDelete);
29768
- sessionDelete = undefined;
29769
- }
29770
- }
29771
- },
29772
- async getAccounts() {
29773
- const provider = await this.getProvider();
29774
- return provider.accounts.map((x) => getAddress(x));
29775
- },
29776
- async getProvider() {
29777
- async function initProvider() {
29778
- const optionalChains = config.chains.map((x) => x.id);
29779
- if (!optionalChains.length)
29780
- return;
29781
- const { EthereumProvider } = await import('./index.es-BXf9jwuI.js');
29782
- const rawProvider = await EthereumProvider.init({
29783
- ...restParameters,
29784
- disableProviderPing: true,
29785
- optionalChains,
29786
- projectId: restParameters.projectId,
29787
- rpcMap: Object.fromEntries(config.chains.map((chain) => {
29788
- const [url] = extractRpcUrls({
29789
- chain,
29790
- transports: config.transports,
29791
- });
29792
- return [chain.id, url];
29793
- })),
29794
- showQrModal: false,
29795
- // We need to specify a custom storage prefix to avoid conflicts with Wagmi's walletConnect instance
29796
- // https://docs.reown.com/walletkit/web/usage#core-instance-sharing
29797
- customStoragePrefix: "squid-hedera",
29798
- });
29799
- const proxiedProvider = new Proxy(rawProvider, {
29800
- get(target, prop, receiver) {
29801
- if (prop === "request") {
29802
- return async (args) => {
29803
- const signingMethods = [
29804
- "eth_sendTransaction",
29805
- "eth_signTransaction",
29806
- ];
29807
- if (signingMethods.includes(args.method)) {
29808
- try {
29809
- HederaExtensionHelper.extensionOpen(extension.id);
29810
- }
29811
- catch { }
29812
- }
29813
- // forward request to original provider
29814
- return target.request(args);
29815
- };
29816
- }
29817
- // forward all other properties/methods
29818
- return Reflect.get(target, prop, receiver);
29819
- },
29820
- });
29821
- return proxiedProvider;
29822
- }
29823
- if (!provider_) {
29824
- if (!providerPromise)
29825
- providerPromise = initProvider();
29826
- provider_ = await providerPromise;
29827
- provider_?.events.setMaxListeners(Number.POSITIVE_INFINITY);
29828
- }
29829
- return provider_;
29830
- },
29831
- async getChainId() {
29832
- const provider = await this.getProvider();
29833
- return provider.chainId;
29834
- },
29835
- async isAuthorized() {
29836
- try {
29837
- const accounts = await this.getAccounts();
29838
- return accounts.length > 0;
29839
- }
29840
- catch {
29841
- return false;
29842
- }
29843
- },
29844
- onAccountsChanged(accounts) {
29845
- if (accounts.length === 0)
29846
- this.onDisconnect();
29847
- else
29848
- config.emitter.emit("change", {
29849
- accounts: accounts.map((x) => getAddress(x)),
29850
- });
29851
- },
29852
- onChainChanged(chain) {
29853
- const chainId = Number(chain);
29854
- config.emitter.emit("change", { chainId });
29855
- },
29856
- async onConnect(connectInfo) {
29857
- const chainId = Number(connectInfo.chainId);
29858
- const accounts = await this.getAccounts();
29859
- config.emitter.emit("connect", { accounts, chainId });
29860
- },
29861
- async onDisconnect() {
29862
- config.emitter.emit("disconnect");
29863
- const provider = await this.getProvider();
29864
- if (disconnect) {
29865
- provider.removeListener("disconnect", disconnect);
29866
- disconnect = undefined;
29867
- }
29868
- if (sessionDelete) {
29869
- provider.removeListener("session_delete", sessionDelete);
29870
- sessionDelete = undefined;
29871
- }
29872
- if (!connect) {
29873
- connect = this.onConnect.bind(this);
29874
- provider.on("connect", connect);
29875
- }
29876
- },
29877
- onDisplayUri(uri) {
29878
- config.emitter.emit("message", { type: "display_uri", data: uri });
29879
- HederaExtensionHelper.extensionConnect(extension.id, uri);
29880
- },
29881
- onSessionDelete() {
29882
- this.onDisconnect();
29883
- },
29884
- }));
29885
- }
29886
-
29887
- const createWagmiConfig = (squidChains, hederaExtensions) => {
29888
- const filteredEvmChains = squidChains.filter((chain) => chain.chainType === ChainType.EVM);
29889
- if (filteredEvmChains.length === 0) {
29890
- throw new Error("At least one chain is required");
29891
- }
29892
- const wagmiChains = filteredEvmChains.map((chain) => {
29893
- return defineChain({
29894
- id: Number(chain.chainId),
29895
- name: chain.networkName,
29896
- nativeCurrency: {
29897
- name: chain.nativeCurrency.name,
29898
- symbol: chain.nativeCurrency.symbol,
29899
- decimals: chain.nativeCurrency.decimals,
29900
- },
29901
- rpcUrls: {
29902
- public: {
29903
- http: [chain.rpc],
29904
- },
29905
- default: {
29906
- http: [chain.rpc],
29907
- },
29908
- },
29909
- });
29910
- });
29911
- const wcMetadata = {
29912
- url: SQUID_METADATA.url,
29913
- name: SQUID_METADATA.name,
29914
- icons: [SQUID_METADATA.icon],
29915
- description: SQUID_METADATA.description,
29916
- };
29917
- return createConfig({
29918
- chains: wagmiChains,
29919
- transports: Object.fromEntries(wagmiChains.map((chain) => [
29920
- chain.id,
29921
- http(chain.rpcUrls.public.http[0] ?? ""),
29922
- ])),
29923
- connectors: [
29924
- injected(),
29925
- safe({
29926
- allowedDomains: [/app.safe.global$/],
29927
- }),
29928
- metaMask({
29929
- dappMetadata: {
29930
- name: SQUID_METADATA.name,
29931
- url: SQUID_METADATA.url,
29932
- iconUrl: SQUID_METADATA.icon,
29933
- },
29934
- }),
29935
- coinbaseWallet({
29936
- appName: SQUID_METADATA.name,
29937
- appLogoUrl: SQUID_METADATA.icon,
29938
- }),
29939
- walletConnect({
29940
- projectId: WALLETCONNECT_PROJECT_ID,
29941
- metadata: wcMetadata,
29942
- }),
29943
- ...hederaExtensions.map((extension) => hederaWalletConnect({
29944
- projectId: WALLETCONNECT_PROJECT_ID,
29945
- metadata: wcMetadata,
29946
- extension,
29947
- })),
29948
- ],
30038
+ const balance = useMemo(() => {
30039
+ if (nativeToken?.decimals && rawBalance) {
30040
+ return {
30041
+ decimals: nativeToken.decimals,
30042
+ value: parseToBigInt(rawBalance, nativeToken.decimals),
30043
+ };
30044
+ }
30045
+ }, [nativeToken?.decimals, rawBalance]);
30046
+ return {
30047
+ balance,
30048
+ isLoading,
30049
+ };
30050
+ };
30051
+ const useXrplNativeBalance = ({ address, chain, }) => {
30052
+ const { nativeToken } = useNativeTokenForChain(chain);
30053
+ const { balance: rawBalance, isLoading } = useXrplBalance({
30054
+ chain,
30055
+ token: nativeToken,
30056
+ userAddress: address,
30057
+ enabled: chain?.chainType === ChainType.XRPL,
29949
30058
  });
30059
+ const balance = useMemo(() => {
30060
+ if (nativeToken?.decimals && rawBalance) {
30061
+ return {
30062
+ decimals: nativeToken.decimals,
30063
+ value: parseToBigInt(rawBalance, nativeToken.decimals),
30064
+ };
30065
+ }
30066
+ }, [nativeToken?.decimals, rawBalance]);
30067
+ return {
30068
+ balance,
30069
+ isLoading,
30070
+ };
29950
30071
  };
29951
- // Taken from wagmi docs
29952
- // https://wagmi.sh/react/guides/ethers
29953
- function clientToSigner(client) {
29954
- const { account, chain, transport } = client;
29955
- if (!account || !chain || !transport) {
29956
- return undefined;
29957
- }
29958
- const network = {
29959
- chainId: chain.id,
29960
- name: chain.name,
29961
- ensAddress: chain.contracts?.ensRegistry?.address,
30072
+ const useStellarNativeBalance = ({ address, chain, }) => {
30073
+ const { nativeToken } = useNativeTokenForChain(chain);
30074
+ const { balance: rawBalance, isLoading } = useStellarBalance({
30075
+ chain,
30076
+ token: nativeToken,
30077
+ userAddress: address,
30078
+ enabled: chain?.chainType === ChainType.STELLAR,
30079
+ });
30080
+ const balance = useMemo(() => {
30081
+ if (nativeToken?.decimals && rawBalance) {
30082
+ return {
30083
+ decimals: nativeToken.decimals,
30084
+ value: parseToBigInt(rawBalance, nativeToken.decimals),
30085
+ };
30086
+ }
30087
+ }, [nativeToken?.decimals, rawBalance]);
30088
+ return {
30089
+ balance,
30090
+ isLoading,
29962
30091
  };
29963
- const provider = new BrowserProvider(transport, network);
29964
- const signer = new JsonRpcSigner(provider, account.address);
29965
- return signer;
29966
- }
29967
-
29968
- function useEvmSigner({ chainId }) {
29969
- const { connector } = useAccount();
29970
- const { data: client } = useWalletClient({ chainId, connector });
29971
- const signer = useMemo(() => (client ? clientToSigner(client) : undefined), [client]);
29972
- return { signer };
29973
- }
29974
- const useSigner = ({ chain }) => {
29975
- const evmChainId = chain?.chainType === ChainType.EVM ? Number(chain.chainId) : undefined;
29976
- // EVM and Cosmos need a different signer for each chain
29977
- // This is not the case for Solana or Bitcoin as there's only one chain in those ecosystems
29978
- const { signer: evmSigner } = useEvmSigner({ chainId: evmChainId });
29979
- const { signer: cosmosSigner } = useCosmosSigner({ chain });
29980
- const { signer: solanaSigner } = useSolanaContext();
29981
- const { signer: bitcoinSigner } = useBitcoinContext();
29982
- const { signer: suiSigner } = useSuiContext();
29983
- const { signer: xrplSigner } = useXrplContext();
29984
- const { signer: stellarSigner } = useStellarContext();
29985
- const isEvmSignerReady = !!evmSigner;
29986
- const isSolanaSignerReady = !!solanaSigner;
29987
- const isCosmosSignerReady = !!cosmosSigner;
29988
- const isBitcoinSignerReady = !!bitcoinSigner;
29989
- const isSuiSignerReady = !!suiSigner;
29990
- const isXrplSignerReady = !!xrplSigner;
29991
- const isStellarSignerReady = !!stellarSigner;
29992
- const isSignerReady = useMemo(() => {
30092
+ };
30093
+ const useNativeBalance = (chain) => {
30094
+ const { connectedAddresses } = useWallet();
30095
+ const { data: cosmosAddressForChain } = useCosmosForChain(chain);
30096
+ // Cosmos is a special case because the address changes on every chain
30097
+ // so we can't use the default cosmos connected address
30098
+ const { balance: nativeCosmosBalance, isLoading: isCosmosLoading } = useCosmosNativeBalance({
30099
+ address: cosmosAddressForChain,
30100
+ chain,
30101
+ });
30102
+ const { balance: nativeEvmBalance, isLoading: isEvmLoading } = useEvmNativeBalance({ address: connectedAddresses[ChainType.EVM], chain });
30103
+ const { balance: nativeBitcoinBalance, isLoading: isBitcoinLoading } = useBitcoinNativeBalance({
30104
+ address: connectedAddresses[ChainType.BTC],
30105
+ chain,
30106
+ });
30107
+ const { balance: nativeSolanaBalance, isLoading: isSolanaLoading } = useSolanaNativeBalance({
30108
+ address: connectedAddresses[ChainType.SOLANA],
30109
+ chain,
30110
+ });
30111
+ const { balance: nativeSuiBalance, isLoading: isSuiLoading } = useSuiNativeBalance({
30112
+ address: connectedAddresses[ChainType.SUI],
30113
+ chain,
30114
+ });
30115
+ const { balance: nativeXrplBalance, isLoading: isXrpLoading } = useXrplNativeBalance({
30116
+ address: connectedAddresses[ChainType.XRPL],
30117
+ chain,
30118
+ });
30119
+ const { balance: nativeStellarBalance, isLoading: isStellarLoading } = useStellarNativeBalance({
30120
+ address: connectedAddresses[ChainType.STELLAR],
30121
+ chain,
30122
+ });
30123
+ const { nativeBalance, nativeBalanceFormatted } = useMemo(() => {
30124
+ let balance;
30125
+ switch (chain?.chainType) {
30126
+ case ChainType.EVM:
30127
+ balance = nativeEvmBalance;
30128
+ break;
30129
+ case ChainType.COSMOS:
30130
+ balance = nativeCosmosBalance;
30131
+ break;
30132
+ case ChainType.BTC:
30133
+ balance = nativeBitcoinBalance;
30134
+ break;
30135
+ case ChainType.SOLANA:
30136
+ balance = nativeSolanaBalance;
30137
+ break;
30138
+ case ChainType.SUI:
30139
+ balance = nativeSuiBalance;
30140
+ break;
30141
+ case ChainType.XRPL:
30142
+ balance = nativeXrplBalance;
30143
+ break;
30144
+ case ChainType.STELLAR:
30145
+ balance = nativeStellarBalance;
30146
+ }
30147
+ const balanceFormatted = !!balance
30148
+ ? formatBNToReadable(balance.value, balance.decimals)
30149
+ : undefined;
30150
+ return {
30151
+ nativeBalance: balance,
30152
+ nativeBalanceFormatted: balanceFormatted,
30153
+ };
30154
+ }, [
30155
+ chain?.chainType,
30156
+ nativeEvmBalance,
30157
+ nativeCosmosBalance,
30158
+ nativeBitcoinBalance,
30159
+ nativeSolanaBalance,
30160
+ nativeSuiBalance,
30161
+ nativeXrplBalance,
30162
+ nativeStellarBalance,
30163
+ ]);
30164
+ const isLoading = useMemo(() => {
29993
30165
  if (!chain?.chainType)
29994
30166
  return false;
29995
30167
  switch (chain.chainType) {
29996
30168
  case ChainType.EVM:
29997
- return isEvmSignerReady;
30169
+ return isEvmLoading;
29998
30170
  case ChainType.COSMOS:
29999
- return isCosmosSignerReady;
30171
+ return isCosmosLoading;
30000
30172
  case ChainType.BTC:
30001
- return isBitcoinSignerReady;
30173
+ return isBitcoinLoading;
30002
30174
  case ChainType.SOLANA:
30003
- return isSolanaSignerReady;
30175
+ return isSolanaLoading;
30004
30176
  case ChainType.SUI:
30005
- return isSuiSignerReady;
30177
+ return isSuiLoading;
30006
30178
  case ChainType.XRPL:
30007
- return isXrplSignerReady;
30179
+ return isXrpLoading;
30008
30180
  case ChainType.STELLAR:
30009
- return isStellarSignerReady;
30181
+ return isStellarLoading;
30010
30182
  }
30011
30183
  }, [
30012
30184
  chain?.chainType,
30013
- isEvmSignerReady,
30014
- isCosmosSignerReady,
30015
- isBitcoinSignerReady,
30016
- isSolanaSignerReady,
30017
- isSuiSignerReady,
30018
- isXrplSignerReady,
30019
- isStellarSignerReady,
30185
+ isEvmLoading,
30186
+ isCosmosLoading,
30187
+ isBitcoinLoading,
30188
+ isSolanaLoading,
30189
+ isSuiLoading,
30190
+ isXrpLoading,
30191
+ isStellarLoading,
30020
30192
  ]);
30021
- return {
30022
- isSignerReady,
30023
- evmSigner,
30024
- cosmosSigner,
30025
- bitcoinSigner,
30026
- solanaSigner,
30027
- suiSigner,
30028
- xrplSigner,
30029
- stellarSigner,
30030
- };
30031
- };
30032
-
30033
- function useHederaTokenAssociations({ address, chain, token }) {
30034
- const publicClient = usePublicClient({
30035
- chainId: Number(CHAIN_IDS.HEDERA),
30036
- });
30037
- const { evmSigner } = useSigner({ chain });
30038
- const queryClient = useQueryClient();
30039
- /**
30040
- * Creates a token association transaction where the destination account authorizes to receive the given token
30041
- */
30042
- const associateToken = useMutation({
30043
- mutationFn: async () => {
30044
- try {
30045
- if (!evmSigner) {
30046
- throw new Error("EVM signer not found");
30047
- }
30048
- if (chain?.chainId !== CHAIN_IDS.HEDERA ||
30049
- token?.chainId !== CHAIN_IDS.HEDERA) {
30050
- throw new Error("Chain and token to associate must be on Hedera");
30051
- }
30052
- const tokenAddress = parseEvmAddress(token.address);
30053
- if (!tokenAddress) {
30054
- throw new Error("Invalid token address");
30055
- }
30056
- const userAddress = parseEvmAddress(address);
30057
- if (!userAddress) {
30058
- throw new Error("Invalid user address");
30059
- }
30060
- const encodedData = encodeFunctionData({
30061
- abi: hrc20,
30062
- functionName: "associate",
30063
- args: [],
30064
- });
30065
- const txRes = await evmSigner.sendTransaction({
30066
- data: encodedData,
30067
- to: tokenAddress,
30068
- chainId: chain.chainId,
30069
- });
30070
- const receipt = await txRes.wait();
30071
- if (receipt?.status !== 1) {
30072
- throw new Error(`Transaction failed with status: ${receipt?.status}`);
30073
- }
30074
- return true;
30075
- }
30076
- catch (error) {
30077
- console.error("Error associating Hedera token:", error);
30078
- return false;
30079
- }
30080
- },
30081
- async onSuccess() {
30082
- queryClient.refetchQueries({
30083
- queryKey: getPrefixKey(QueryKeys.IsHederaTokenAssociated),
30084
- });
30085
- },
30086
- });
30087
- /**
30088
- * Checks if the destination account has associated the given token.
30089
- *
30090
- * Hedera requires accounts to associate a token before being able to receive it.
30091
- *
30092
- * Accounts which have max. associations set to -1 can receive any token without previous association
30093
- */
30094
- const isTokenAssociated = useQuery({
30095
- queryKey: keys().isHederaTokenAssociated(address, token?.chainId, token?.type, token?.address),
30096
- queryFn: async () => {
30097
- if (token?.chainId !== CHAIN_IDS.HEDERA) {
30098
- return true;
30099
- }
30100
- // The native HBAR token doesn't need an association
30101
- if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase()) {
30102
- return true;
30103
- }
30104
- if (!chain || !address || !publicClient) {
30105
- throw new Error("Missing required parameters");
30106
- }
30107
- // TODO: update types
30108
- const apiUrl = chain?.chainConfig?.hedera?.mirrorNodeUrl;
30109
- if (!apiUrl) {
30110
- throw new Error("Missing Hedera mirror node URL in chain config");
30111
- }
30112
- const hederaApiClient = new HederaApiClient(apiUrl);
30113
- return hederaApiClient.isTokenAssociated({
30114
- address,
30115
- token,
30116
- });
30117
- },
30118
- enabled: !!address && !!publicClient && token?.chainId === CHAIN_IDS.HEDERA,
30119
- });
30120
- return {
30121
- isTokenAssociated,
30122
- associateToken,
30123
- };
30124
- }
30125
-
30126
- const useKeyboardNavigation = ({ onEscape }) => {
30127
- const onKeyDown = useCallback((event) => {
30128
- if (event.key === "Escape") {
30129
- onEscape?.();
30130
- return;
30131
- }
30132
- }, [onEscape]);
30133
- useEffect(() => {
30134
- document.addEventListener("keydown", onKeyDown, false);
30135
- return () => {
30136
- document.removeEventListener("keydown", onKeyDown, false);
30137
- };
30138
- }, [onKeyDown]);
30139
- };
30140
-
30141
- const useSquidQueryClient = () => {
30142
- const queryClient = useQueryClient();
30143
- const invalidateQueries = (key) => {
30144
- const prefixKey = getPrefixKey(key);
30145
- queryClient.invalidateQueries(prefixKey);
30146
- };
30147
- const refetchQueries = (key) => {
30148
- const prefixKey = getPrefixKey(key);
30149
- queryClient.refetchQueries(prefixKey);
30150
- };
30151
- const invalidateAndRefetchQueries = (key) => {
30152
- invalidateQueries(key);
30153
- refetchQueries(key);
30154
- };
30155
- return {
30156
- invalidateQueries,
30157
- refetchQueries,
30158
- invalidateAndRefetchQueries,
30159
- };
30193
+ return { nativeBalance, nativeBalanceFormatted, isLoading };
30160
30194
  };
30161
30195
 
30162
- class StellarApiClient {
30163
- apiUrl;
30164
- constructor(apiUrl) {
30165
- this.apiUrl = apiUrl;
30166
- }
30167
- async getBaseReserve() {
30168
- const response = await fetch(`${this.apiUrl}/ledgers?order=desc&limit=1`);
30169
- if (!response.ok) {
30170
- throw new Error(`Failed to fetch ledgers: ${response.status}`);
30171
- }
30172
- const ledgers = await response.json();
30173
- const latestLedger = ledgers?._embedded.records?.[0];
30174
- if (latestLedger?.base_reserve_in_stroops == null) {
30175
- throw new Error("Invalid ledger data");
30176
- }
30177
- const baseReserveBn = BigInt(latestLedger.base_reserve_in_stroops);
30178
- return baseReserveBn;
30179
- }
30180
- }
30181
-
30182
- const DEFAULT_REFETCH_INTERVAL$1 = 20_000;
30183
- function useStellarAccountActivation({ address, chain, token, }) {
30184
- /**
30185
- * Checks if the destination account exists on the Stellar network
30186
- * Stellar accounts need to have a minimum balance before they can receive payments
30187
- */
30188
- const accountActivatedInfo = useQuery({
30189
- queryKey: keys().stellarAccountActivatedInfo(address, chain?.chainId, chain?.chainType),
30190
- queryFn: async () => {
30191
- if (chain?.chainType !== ChainType.STELLAR ||
30192
- token?.type !== ChainType.STELLAR) {
30193
- return null;
30194
- }
30195
- if (!address) {
30196
- throw new Error("Destination address is required");
30197
- }
30198
- // TODO: update types
30199
- const [horizonApiUrl] = chain?.horizonRpcList;
30200
- if (typeof horizonApiUrl !== "string") {
30201
- throw new Error("Invalid Horizon API URL");
30202
- }
30203
- const stellarApiClient = new StellarApiClient(horizonApiUrl);
30204
- const reserveBase = await stellarApiClient.getBaseReserve();
30205
- // Stellar accounts require two base reserves to be activated
30206
- // https://developers.stellar.org/docs/learn/fundamentals/lumens#minimum-balance
30207
- const accountReserveBase = reserveBase * BigInt(2);
30208
- const stellarRpcClient = await getClient(chain);
30209
- const isActivated = await stellarRpcClient.isAccountActivated(address);
30210
- return {
30211
- isActivated,
30212
- reserveBaseBn: accountReserveBase,
30213
- };
30214
- },
30215
- enabled: !!address && chain?.chainType === ChainType.STELLAR,
30216
- refetchInterval: DEFAULT_REFETCH_INTERVAL$1,
30217
- refetchOnWindowFocus: true,
30196
+ function useHederaAccountActivation({ address, chain, token }) {
30197
+ const { balance: destNativeEvmBalance } = useEvmNativeBalance({
30198
+ chain,
30199
+ address,
30218
30200
  });
30201
+ const isHederaAccountActivated = useMemo(() => {
30202
+ if (token?.chainId !== CHAIN_IDS.HEDERA)
30203
+ return true;
30204
+ if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase())
30205
+ return true;
30206
+ return (!!destNativeEvmBalance?.value && destNativeEvmBalance.value > BigInt(0));
30207
+ }, [token?.chainId, token?.address, destNativeEvmBalance?.value]);
30219
30208
  return {
30220
- accountActivatedInfo,
30209
+ isHederaAccountActivated,
30221
30210
  };
30222
30211
  }
30223
30212
 
@@ -30745,161 +30734,6 @@ const useSingleTokenPrice = (tokenData) => {
30745
30734
  return { tokenPrice, getUSDValue };
30746
30735
  };
30747
30736
 
30748
- const TEMPO_FEE_MANAGER_ADDRESS = "0xfeec000000000000000000000000000000000000";
30749
- const feeManagerAbi = [
30750
- {
30751
- name: "userTokens",
30752
- type: "function",
30753
- stateMutability: "view",
30754
- inputs: [{ type: "address", name: "user" }],
30755
- outputs: [{ type: "address" }],
30756
- },
30757
- ];
30758
- const isTempoChain = (chainId) => chainId === CHAIN_IDS.TEMPO;
30759
- /**
30760
- * Convert a fee amount from virtual USD (18 decimals, attodollars)
30761
- * to 6-decimal TIP-20 stablecoin units (microdollars).
30762
- * All TIP-20 tokens on Tempo have 6 decimals.
30763
- */
30764
- const convertTempoFeeToStablecoinUnits = (feeIn18Dec) => feeIn18Dec / BigInt(10 ** 12);
30765
- /**
30766
- * Pure function that derives TempoFeeData from on-chain query results.
30767
- * Extracted from useTempoFeeCheck so the branching logic is unit-testable
30768
- * without mocking React hooks.
30769
- */
30770
- function resolveTempoFeeData({ hasAccountFeePreference, accountGasTokenAddress, accountGasTokenBalance, fromTokenAddress, fromTokenBalance, }) {
30771
- if (hasAccountFeePreference && accountGasTokenAddress) {
30772
- const gasTokenIsFromToken = !!fromTokenAddress &&
30773
- accountGasTokenAddress.toLowerCase() === fromTokenAddress.toLowerCase();
30774
- return {
30775
- gasTokenBalance: accountGasTokenBalance ?? BigInt(0),
30776
- gasTokenIsFromToken,
30777
- gasTokenAddress: accountGasTokenAddress,
30778
- };
30779
- }
30780
- if (fromTokenAddress != null && fromTokenBalance != null) {
30781
- return {
30782
- gasTokenBalance: fromTokenBalance,
30783
- gasTokenIsFromToken: true,
30784
- gasTokenAddress: fromTokenAddress,
30785
- };
30786
- }
30787
- return null;
30788
- }
30789
- /**
30790
- * Resolves the token that pays network gas fees for a given chain and transaction context.
30791
- * For Tempo chains, this is the dynamically resolved gas token (from tempoFeeData).
30792
- * For all other chains, this is the static native gas token.
30793
- */
30794
- function resolveGasToken({ nativeToken, chain, tempoFeeData, evmTokens, }) {
30795
- if (!chain)
30796
- return undefined;
30797
- if (isTempoChain(chain.chainId)) {
30798
- if (!tempoFeeData)
30799
- return undefined;
30800
- return evmTokens.find((t) => t.chainId === chain.chainId &&
30801
- t.address.toLowerCase() === tempoFeeData.gasTokenAddress.toLowerCase());
30802
- }
30803
- return nativeToken;
30804
- }
30805
- /**
30806
- * Resolves chain-agnostic fee parameters from chain-specific inputs.
30807
- * This is the single place that knows about Tempo vs. native-token fee semantics.
30808
- *
30809
- * Safe defaults when tempoFeeData is missing on a Tempo chain: balance=0 and
30810
- * fromTokenPaysNetworkFee=false, so the UI blocks rather than misleads.
30811
- */
30812
- function resolveChainFeeParams({ fromChainId, tempoFeeData, isFromTokenNative, nativeBalanceWei, }) {
30813
- if (isTempoChain(fromChainId)) {
30814
- if (!tempoFeeData) {
30815
- return null;
30816
- }
30817
- return {
30818
- fromTokenPaysNetworkFee: tempoFeeData?.gasTokenIsFromToken ?? false,
30819
- gasTokenBalanceWei: tempoFeeData?.gasTokenBalance ?? BigInt(0),
30820
- normalizeFee: convertTempoFeeToStablecoinUnits,
30821
- };
30822
- }
30823
- return {
30824
- fromTokenPaysNetworkFee: isFromTokenNative,
30825
- gasTokenBalanceWei: nativeBalanceWei,
30826
- normalizeFee: (fee) => fee,
30827
- };
30828
- }
30829
-
30830
- const BALANCE_QUERY_STALE_TIME = 10_000;
30831
- /**
30832
- * Returns raw on-chain gas token data for Tempo chains, or null when the source
30833
- * chain is not Tempo.
30834
- */
30835
- const useTempoFeeCheck = ({ fromChain, fromToken, }) => {
30836
- const { connectedAddresses } = useWallet();
30837
- const evmAddress = parseEvmAddress(connectedAddresses[ChainType.EVM]);
30838
- const isTempo = isTempoChain(fromChain?.chainId);
30839
- const chainId = Number(fromChain?.chainId);
30840
- // Read account-level gas token preference from FeeManager precompile
30841
- // See docs: https://docs.tempo.xyz/protocol/fees/spec-fee#account-level
30842
- const { data: accountGasTokenAddress } = useReadContract({
30843
- address: TEMPO_FEE_MANAGER_ADDRESS,
30844
- abi: feeManagerAbi,
30845
- functionName: "userTokens",
30846
- args: evmAddress ? [evmAddress] : undefined,
30847
- chainId,
30848
- query: {
30849
- enabled: isTempo && !!evmAddress,
30850
- staleTime: 30_000,
30851
- },
30852
- });
30853
- const hasAccountFeePreference = !!accountGasTokenAddress &&
30854
- // By default, the zero address is returned when the user has no preference set
30855
- zeroAddress$1.toLowerCase() !== accountGasTokenAddress.toLowerCase();
30856
- // Fetch balance of the account-preferred gas token (if set)
30857
- const { data: accountGasTokenBalance } = useBalance({
30858
- address: evmAddress,
30859
- token: hasAccountFeePreference ? accountGasTokenAddress : undefined,
30860
- chainId,
30861
- query: {
30862
- enabled: isTempo && hasAccountFeePreference && !!evmAddress,
30863
- staleTime: BALANCE_QUERY_STALE_TIME,
30864
- },
30865
- });
30866
- const fromTokenAddress = parseEvmAddress(fromToken?.address);
30867
- const { data: fromTokenBalance } = useBalance({
30868
- address: evmAddress,
30869
- token: fromTokenAddress,
30870
- chainId,
30871
- query: {
30872
- enabled: isTempo && !!evmAddress,
30873
- staleTime: BALANCE_QUERY_STALE_TIME,
30874
- },
30875
- });
30876
- if (!isTempo)
30877
- return null;
30878
- return resolveTempoFeeData({
30879
- hasAccountFeePreference,
30880
- accountGasTokenAddress,
30881
- accountGasTokenBalance: accountGasTokenBalance?.value,
30882
- fromTokenAddress,
30883
- fromTokenBalance: fromTokenBalance?.value,
30884
- });
30885
- };
30886
-
30887
- /**
30888
- * Resolves the token that pays network gas fees for a given chain
30889
- */
30890
- function useSourceChainGasToken({ fromChain, fromToken, }) {
30891
- const { nativeToken } = useNativeTokenForChain(fromChain);
30892
- const { evmTokens } = useSquidTokens();
30893
- const tempoFeeData = useTempoFeeCheck({ fromChain, fromToken });
30894
- const gasToken = useMemo(() => resolveGasToken({
30895
- nativeToken,
30896
- chain: fromChain,
30897
- tempoFeeData,
30898
- evmTokens,
30899
- }), [nativeToken, fromChain, tempoFeeData, evmTokens]);
30900
- return { gasToken };
30901
- }
30902
-
30903
30737
  const MAX_COINGECKO_QUERY_TOKENS = 100;
30904
30738
  const fetchHistoricalData = async (coingeckoId, timeFrame) => {
30905
30739
  const now = Math.floor(Date.now() / 1000);
@@ -31050,20 +30884,24 @@ const calculateTotalNativeFees = ({ expressFeeCost, firstFeeCost, firstGasCost,
31050
30884
  (sameTokenBetweenFees
31051
30885
  ? BigInt(firstFeeCost?.amount ?? "0") + BigInt(firstGasCost?.amount ?? "0")
31052
30886
  : BigInt(firstGasCost?.amount ?? "0"));
31053
- const isGasBalanceEnough = ({ fromAmount, networkFeesWei, chainFeeParams, }) => {
31054
- if (!chainFeeParams)
31055
- return false;
31056
- if (chainFeeParams.fromTokenPaysNetworkFee) {
31057
- return (BigInt(fromAmount ?? "0") + networkFeesWei <=
31058
- chainFeeParams.gasTokenBalanceWei);
31059
- }
31060
- return networkFeesWei <= chainFeeParams.gasTokenBalanceWei;
31061
- };
31062
- const calculateMinAmountValueWarnMsg = ({ networkFeesWei, chainFeeParams, }) => {
31063
- if (!chainFeeParams?.fromTokenPaysNetworkFee)
31064
- return undefined;
31065
- return chainFeeParams.gasTokenBalanceWei - networkFeesWei;
31066
- };
30887
+ const isFromBalanceEnoughToSwap = ({ isFromTokenNative, fromAmount, totalFeesInNativeTokenPlusRatio, nativeTokenBalanceFromChainWei, }) => {
30888
+ const fromAmountBigInt = BigInt(fromAmount ?? "0");
30889
+ const totalFeesInNativeTokenPlusRatioBigInt = totalFeesInNativeTokenPlusRatio;
30890
+ const nativeTokenBalanceFromChainWeiBigInt = nativeTokenBalanceFromChainWei;
30891
+ return isFromTokenNative
30892
+ ? fromAmountBigInt + totalFeesInNativeTokenPlusRatioBigInt <=
30893
+ nativeTokenBalanceFromChainWeiBigInt
30894
+ : totalFeesInNativeTokenPlusRatioBigInt <=
30895
+ nativeTokenBalanceFromChainWeiBigInt;
30896
+ };
30897
+ const calculateMinAmountValueWarnMsg = ({ isFromTokenNative, nativeTokenBalanceFromChainWei, sourceChainNativeTokenDecimals, totalFeesInNativeTokenPlusRatio, }) => isFromTokenNative
30898
+ ? (() => {
30899
+ const minAmount = nativeTokenBalanceFromChainWei - totalFeesInNativeTokenPlusRatio;
30900
+ return minAmount > BigInt(0)
30901
+ ? formatBNToReadable(minAmount, sourceChainNativeTokenDecimals)
30902
+ : "0";
30903
+ })()
30904
+ : undefined;
31067
30905
  /**
31068
30906
  * Calculates the estimated duration of a route
31069
30907
  *
@@ -31102,10 +30940,12 @@ const formatEstimatedRouteDuration = ({ estimatedRouteDuration, isSingleChainRou
31102
30940
  * @returns {Object} An object containing various estimate results and calculations, including token information,
31103
30941
  * amounts, fees, gas costs, and other relevant data for the transaction.
31104
30942
  */
31105
- const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, collectFees, nativeTokenBalanceFromChainWei, tempoFeeData, }) => {
30943
+ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, collectFees, nativeTokenBalanceFromChainWei, }) => {
31106
30944
  const fromToken = findToken(tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken);
31107
30945
  const fromAmount = squidRoute?.estimate?.fromAmount;
31108
30946
  const fromAmountFormatted = formatAmount(fromAmount, fromToken?.decimals);
30947
+ const sourceChainNativeToken = findNativeToken(tokens, fromChain);
30948
+ const destChainNativeToken = findNativeToken(tokens, toChain);
31109
30949
  const toAmountUSD = squidRoute?.estimate?.toAmountUSD;
31110
30950
  const exchangeRate = squidRoute?.estimate.exchangeRate ?? "0";
31111
30951
  const toAmountMinUSD = squidRoute?.estimate.toAmountMinUSD ?? "0";
@@ -31124,6 +30964,10 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31124
30964
  const expectedGasRefundCostUSD = convertTokenAmountToUSD(formatBNToReadable(expectedGasRefundCost, firstFeeCost?.token.decimals ?? 18), firstFeeCost?.token.usdPrice ?? "0");
31125
30965
  const sameTokenBetweenFees = firstFeeCost?.token.address === firstGasCost?.token.address &&
31126
30966
  firstFeeCost?.token.chainId === firstGasCost?.token.chainId;
30967
+ const isFromTokenNative =
30968
+ // TODO: temporary fix, currently nativeCurrency.symbol is not always in uppercase
30969
+ fromToken?.symbol.toUpperCase() ===
30970
+ fromChain?.nativeCurrency.symbol.toUpperCase();
31127
30971
  const totalNativeFees = calculateTotalNativeFees({
31128
30972
  expressFeeCost,
31129
30973
  firstFeeCost,
@@ -31131,32 +30975,19 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31131
30975
  sameTokenBetweenFees,
31132
30976
  });
31133
30977
  const totalFeesInNativeTokenPlusRatio = (totalNativeFees * BigInt(110)) / BigInt(100);
31134
- const isNativeTokenFromChain =
31135
- // TODO: nativeCurrency.symbol is not always uppercase
31136
- fromToken?.symbol.toUpperCase() ===
31137
- fromChain?.nativeCurrency.symbol.toUpperCase();
31138
- const chainFeeParams = resolveChainFeeParams({
31139
- tempoFeeData,
31140
- isFromTokenNative: isNativeTokenFromChain,
31141
- nativeBalanceWei: nativeTokenBalanceFromChainWei,
31142
- fromChainId: fromChain?.chainId,
31143
- });
31144
- const networkFeesWei = chainFeeParams?.normalizeFee(totalFeesInNativeTokenPlusRatio) ?? BigInt(0);
31145
- const gasBalanceEnough = isGasBalanceEnough({
31146
- chainFeeParams,
30978
+ const fromBalanceEnoughToSwap = isFromBalanceEnoughToSwap({
30979
+ isFromTokenNative,
31147
30980
  fromAmount,
31148
- networkFeesWei,
30981
+ fromTokenDecimals: fromToken?.decimals,
30982
+ totalFeesInNativeTokenPlusRatio,
30983
+ nativeTokenBalanceFromChainWei,
31149
30984
  });
31150
- const minAmount = calculateMinAmountValueWarnMsg({
31151
- chainFeeParams,
31152
- // gasTokenDecimals: chainFeeParams,
31153
- networkFeesWei,
30985
+ const minAmountValueWarnMsg = calculateMinAmountValueWarnMsg({
30986
+ isFromTokenNative,
30987
+ nativeTokenBalanceFromChainWei,
30988
+ sourceChainNativeTokenDecimals: sourceChainNativeToken?.decimals,
30989
+ totalFeesInNativeTokenPlusRatio,
31154
30990
  });
31155
- const minAmountValueWarnMsg = minAmount
31156
- ? formatBNToReadable(minAmount, chainFeeParams?.fromTokenPaysNetworkFee
31157
- ? fromToken?.decimals
31158
- : undefined)
31159
- : undefined;
31160
30991
  const isSingleChainRoute = fromChain?.chainId === toChain?.chainId;
31161
30992
  const estimatedRouteDuration = formatEstimatedRouteDuration({
31162
30993
  estimatedRouteDuration: squidRoute?.estimate?.estimatedRouteDuration,
@@ -31166,6 +30997,8 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31166
30997
  fromToken,
31167
30998
  fromAmount,
31168
30999
  fromAmountFormatted,
31000
+ sourceChainNativeToken,
31001
+ destChainNativeToken,
31169
31002
  toAmountUSD,
31170
31003
  exchangeRate,
31171
31004
  toAmountMinUSD,
@@ -31180,10 +31013,10 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31180
31013
  expectedGasRefundCost,
31181
31014
  expectedGasRefundCostUSD,
31182
31015
  sameTokenBetweenFees,
31183
- fromTokenPaysNetworkFee: chainFeeParams?.fromTokenPaysNetworkFee ?? false,
31016
+ isFromTokenNative,
31184
31017
  totalNativeFees,
31185
31018
  totalFeesInNativeTokenPlusRatio,
31186
- gasBalanceEnough,
31019
+ fromBalanceEnoughToSwap,
31187
31020
  minAmountValueWarnMsg,
31188
31021
  estimatedRouteDuration,
31189
31022
  };
@@ -31219,6 +31052,28 @@ const calculateTotalWithRefundEstimate = (allFeeCosts, expectedGasRefundCost, ge
31219
31052
  feeToken: firstFeeCost?.token,
31220
31053
  };
31221
31054
  };
31055
+ /**
31056
+ * Calculates the proposed gas amount for the destination chain.
31057
+ *
31058
+ * @param destChainNativeToken - The symbol of the native token for the destination chain.
31059
+ * @returns An object containing the proposed gas amount value and the currency symbol.
31060
+ */
31061
+ const getProposedGasDestinationAmount = (destChainNativeToken) => {
31062
+ const gasAmounts = {
31063
+ GLMR: 5.289,
31064
+ ETH: 0.0009,
31065
+ AVAX: 0.115,
31066
+ BNB: 0.00425,
31067
+ FTM: 4.45,
31068
+ CELO: 3.052,
31069
+ KAVA: 2.339,
31070
+ MATIC: 1.795,
31071
+ };
31072
+ return {
31073
+ value: gasAmounts[destChainNativeToken ?? ""] ?? 0,
31074
+ currency: destChainNativeToken,
31075
+ };
31076
+ };
31222
31077
 
31223
31078
  function useSendTransactionGas({ chain, token, from, }) {
31224
31079
  return useQuery({
@@ -31240,11 +31095,7 @@ function useSendTransactionGas({ chain, token, from, }) {
31240
31095
  // Some RPC providers require the sender to have enough balance, otherwise estimation reverts
31241
31096
  // so we'll try to use the user provided address when possible
31242
31097
  const sender = from || dummyAddress;
31243
- // Tempo has no native token, so `value` transfers are rejected by the EVM.
31244
- // We can simulate an ERC20 transfer instead
31245
- const supportsNativeTransfers = chain.chainId !== CHAIN_IDS.TEMPO;
31246
- const isNativeToken = token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase();
31247
- if (isNativeToken && supportsNativeTransfers) {
31098
+ if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase()) {
31248
31099
  const gas = await client.estimateGas({
31249
31100
  from: sender,
31250
31101
  to: dummyAddress,
@@ -31264,14 +31115,7 @@ function useSendTransactionGas({ chain, token, from, }) {
31264
31115
  data,
31265
31116
  chainId: chain.chainId,
31266
31117
  });
31267
- const feeWei = gas * maxFeePerGas;
31268
- // Tempo fees are denominated in virtual USD (18 dec, 1e-18 USD units).
31269
- // Convert to 6-dec stablecoin units so all callers receive a
31270
- // consistent unit without needing to know about the chain.
31271
- if (chain.chainId === CHAIN_IDS.TEMPO) {
31272
- return convertTempoFeeToStablecoinUnits(feeWei);
31273
- }
31274
- return feeWei;
31118
+ return gas * maxFeePerGas;
31275
31119
  }
31276
31120
  case ChainType.COSMOS: {
31277
31121
  // TODO: get gas estimation from backend
@@ -31319,24 +31163,18 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31319
31163
  from,
31320
31164
  });
31321
31165
  const { nativeBalance } = useNativeBalance(chain);
31322
- const tempoFeeData = useTempoFeeCheck({ fromChain: chain, fromToken: token });
31323
- const chainFeeParams = resolveChainFeeParams({
31324
- fromChainId: chain?.chainId,
31325
- tempoFeeData,
31326
- isFromTokenNative: token != null &&
31327
- token.address.toLowerCase() ===
31328
- chainTypeToNativeTokenAddressMap[token.type]?.toLowerCase(),
31329
- nativeBalanceWei: nativeBalance?.value ?? BigInt(0),
31330
- });
31331
- const gasBalanceEnough = useMemo(() => {
31332
- if (!amount || !token?.decimals)
31166
+ const isNativeBalanceEnoughToPayGasFees = useMemo(() => {
31167
+ if (!nativeBalance?.value || !amount || !token?.decimals) {
31333
31168
  return false;
31334
- return isGasBalanceEnough({
31335
- fromAmount: parseToBigInt(amount, token.decimals).toString(),
31336
- networkFeesWei: estimatedGas,
31337
- chainFeeParams,
31338
- });
31339
- }, [amount, estimatedGas, token, chainFeeParams]);
31169
+ }
31170
+ const isTokenNative = token.address.toLowerCase() ===
31171
+ chainTypeToNativeTokenAddressMap[token.type].toLowerCase();
31172
+ if (isTokenNative) {
31173
+ return (parseToBigInt(amount, token.decimals) + estimatedGas <=
31174
+ nativeBalance.value);
31175
+ }
31176
+ return estimatedGas <= nativeBalance.value;
31177
+ }, [amount, estimatedGas, nativeBalance?.value, token]);
31340
31178
  const isBalanceEnough = useMemo(() => {
31341
31179
  if (token?.decimals == null || !balance || !amount)
31342
31180
  return false;
@@ -31344,30 +31182,28 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31344
31182
  parseToBigInt(amount, token.decimals));
31345
31183
  }, [amount, balance, token?.decimals]);
31346
31184
  const minAmountValueWarnMsg = useMemo(() => {
31347
- if (!token?.address || !estimatedGas)
31348
- return undefined;
31349
- if (!chainFeeParams)
31185
+ if (!token?.address || !nativeBalance?.value || !estimatedGas)
31350
31186
  return undefined;
31351
- const minAmount = calculateMinAmountValueWarnMsg({
31352
- chainFeeParams,
31353
- // gasTokenDecimals: chainFeeParams.fromTokenPaysNetworkFee
31354
- // ? token.decimals
31355
- // : undefined,
31356
- networkFeesWei: estimatedGas,
31187
+ const isFromTokenNative = token.address.toLowerCase() ===
31188
+ chainTypeToNativeTokenAddressMap[token.type].toLowerCase();
31189
+ return calculateMinAmountValueWarnMsg({
31190
+ isFromTokenNative,
31191
+ nativeTokenBalanceFromChainWei: nativeBalance.value,
31192
+ sourceChainNativeTokenDecimals: nativeBalance.decimals,
31193
+ totalFeesInNativeTokenPlusRatio: estimatedGas,
31357
31194
  });
31358
- // return minAmount > BigInt(0)
31359
- // ? formatBNToReadable(minAmount, gasTokenDecimals)
31360
- // : "0";
31361
- if (!minAmount)
31362
- return undefined;
31363
- return formatBNToReadable(minAmount, chainFeeParams.fromTokenPaysNetworkFee ? token.decimals : undefined);
31364
- }, [estimatedGas, token, chainFeeParams]);
31195
+ }, [
31196
+ estimatedGas,
31197
+ nativeBalance?.decimals,
31198
+ nativeBalance?.value,
31199
+ token?.address,
31200
+ token?.type,
31201
+ ]);
31365
31202
  return {
31366
31203
  estimatedGas,
31367
31204
  isBalanceEnough,
31368
- tokenPaysNetworkFee: chainFeeParams?.fromTokenPaysNetworkFee ?? false,
31369
31205
  isLoading,
31370
- isGasBalanceEnough: gasBalanceEnough,
31206
+ isNativeBalanceEnoughToPayGasFees,
31371
31207
  minAmountValueWarnMsg,
31372
31208
  };
31373
31209
  }
@@ -32426,7 +32262,7 @@ const useApproval = ({ squidRoute, }) => {
32426
32262
  // This is to ensure we're using the latest expiry timestamp
32427
32263
  if (squidRoute) {
32428
32264
  queryClient.refetchQueries({
32429
- queryKey: keys().transaction(squidRoute.params.fromChain, squidRoute.params.toChain, squidRoute.params.toToken, squidRoute.params.fromToken, fromPrice, squidRoute.params.slippage, squidRoute.params.fromAddress, squidRoute.params.bypassGuardrails, squidRoute.params.toAddress, squidRoute.params.fallbackAddresses?.[0]?.address, squidRoute.params.quoteOnly, getChainType(squidRoute.params.fromChain), squidRoute.params.preHook, squidRoute.params.postHook,
32265
+ queryKey: keys().transaction(squidRoute.params.fromChain, squidRoute.params.toChain, squidRoute.params.toToken, squidRoute.params.fromToken, fromPrice, squidRoute.params.slippage, squidRoute.params.receiveGasOnDestination, squidRoute.params.fromAddress, squidRoute.params.bypassGuardrails, squidRoute.params.toAddress, squidRoute.params.fallbackAddresses?.[0]?.address, squidRoute.params.quoteOnly, getChainType(squidRoute.params.fromChain), squidRoute.params.preHook, squidRoute.params.postHook,
32430
32266
  // TODO: update types
32431
32267
  squidRoute.params?.overrideGasRefundAddress),
32432
32268
  });
@@ -32445,10 +32281,8 @@ const AXELAR_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/ass
32445
32281
  const useEstimate = (squidRoute) => {
32446
32282
  const collectFees = useConfigStore((state) => state.config.collectFees);
32447
32283
  const { tokens } = useSquidTokens();
32448
- const { fromChain, toChain, fromPrice } = useSwap();
32284
+ const { fromChain, toChain } = useSwap();
32449
32285
  const { nativeBalance } = useNativeBalance(fromChain);
32450
- const fromToken = useMemo(() => findToken(tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken), [tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken]);
32451
- const tempoFeeData = useTempoFeeCheck({ fromChain, fromToken });
32452
32286
  const estimateResults = useMemo(() => calculateEstimateResults({
32453
32287
  squidRoute,
32454
32288
  tokens,
@@ -32456,17 +32290,8 @@ const useEstimate = (squidRoute) => {
32456
32290
  toChain,
32457
32291
  collectFees: !!collectFees && collectFees.fee > 0,
32458
32292
  nativeTokenBalanceFromChainWei: nativeBalance?.value ?? BigInt("0"),
32459
- tempoFeeData: tempoFeeData ?? undefined,
32460
- }), [
32461
- squidRoute,
32462
- tokens,
32463
- fromChain,
32464
- toChain,
32465
- collectFees,
32466
- nativeBalance,
32467
- tempoFeeData,
32468
- ]);
32469
- const fromBalanceFormatted = useMultiChainBalance({
32293
+ }), [squidRoute, tokens, fromChain, toChain, collectFees, nativeBalance]);
32294
+ const balanceFormatted = useMultiChainBalance({
32470
32295
  chain: fromChain,
32471
32296
  token: estimateResults.fromToken,
32472
32297
  userAddress: squidRoute?.params.fromAddress ?? "",
@@ -32478,6 +32303,7 @@ const useEstimate = (squidRoute) => {
32478
32303
  estimateResults.expectedGasRefundCost,
32479
32304
  getUSDValue,
32480
32305
  ]);
32306
+ const proposedGasDestinationAmount = useMemo(() => getProposedGasDestinationAmount(estimateResults.destChainNativeToken?.symbol), [estimateResults.destChainNativeToken]);
32481
32307
  const { feeCostsFormatted, totalFeeCostsUsd } = useMemo(() => {
32482
32308
  const feeCosts = squidRoute?.estimate.feeCosts ?? [];
32483
32309
  const feeCostsRenamed = [];
@@ -32536,18 +32362,19 @@ const useEstimate = (squidRoute) => {
32536
32362
  totalFeeCostsUsd: totalFeeCostsUsdFormatted,
32537
32363
  };
32538
32364
  }, [squidRoute?.estimate.feeCosts]);
32539
- const slippageFormatted = Number(squidRoute?.estimate?.aggregateSlippage ?? 0).toFixed(2) + "%";
32540
- const fromBalanceEnoughToSwap = useMemo(() => {
32541
- const fromBalanceNum = Number(fromBalanceFormatted ?? 0);
32542
- const fromPriceNum = Number(fromPrice ?? 0);
32543
- return fromBalanceNum >= fromPriceNum;
32544
- }, [fromBalanceFormatted, fromPrice]);
32365
+ const slippageFormatted =
32366
+ // TODO: update types
32367
+ Number(squidRoute?.estimate?.aggregateSlippage ?? 0).toFixed(2) +
32368
+ "%";
32369
+ const enoughBalanceToSwap = +balanceFormatted >= 0 &&
32370
+ +balanceFormatted > +estimateResults.fromAmountFormatted;
32545
32371
  return {
32546
32372
  ...estimateResults,
32547
- fromBalanceFormatted,
32373
+ balanceFormatted,
32548
32374
  slippageFormatted,
32549
32375
  totalWithRefundEstimate,
32550
- fromBalanceEnoughToSwap,
32376
+ proposedGasDestinationAmount,
32377
+ enoughBalanceToSwap,
32551
32378
  feeCostsFormatted,
32552
32379
  totalFeeCostsUsd,
32553
32380
  };
@@ -36295,7 +36122,7 @@ const useGetRoute = () => {
36295
36122
  });
36296
36123
  // Cache the route data
36297
36124
  // Useful when the getRoute mutation is called from another hook
36298
- queryClient.setQueryData(keys().transaction(fromChain, toChain, toToken.address, fromToken.address, fromPrice, config.slippage, sourceUserAddress, config.degenMode, destinationAddress, swapRoute?.fallbackAddress, quoteOnly, fromChainType, config.preHook, config.postHook, overrideGasRefundAddress), route);
36125
+ queryClient.setQueryData(keys().transaction(fromChain, toChain, toToken.address, fromToken.address, fromPrice, config.slippage, config.enableGetGasOnDestination, sourceUserAddress, config.degenMode, destinationAddress, swapRoute?.fallbackAddress, quoteOnly, fromChainType, config.preHook, config.postHook, overrideGasRefundAddress), route);
36299
36126
  return route;
36300
36127
  });
36301
36128
  };
@@ -36318,13 +36145,14 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36318
36145
  const sourceUserAddress = isDepositAddressEnabled && isAvailableAsPaymentMethod
36319
36146
  ? depositRefundAddress ?? sourceConnectedAddress
36320
36147
  : sourceConnectedAddress;
36321
- const squidRouteQueryKeys = useMemo(() => keys().transaction(fromChain?.chainId, toChain?.chainId, toToken?.address, fromToken?.address, fromPrice, config.slippage, sourceUserAddress, config.degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChain?.chainType, config.preHook, config.postHook, config.overrideGasRefundAddress), [
36148
+ const squidRouteQueryKeys = useMemo(() => keys().transaction(fromChain?.chainId, toChain?.chainId, toToken?.address, fromToken?.address, fromPrice, config.slippage, config.enableGetGasOnDestination, sourceUserAddress, config.degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChain?.chainType, config.preHook, config.postHook, config.overrideGasRefundAddress), [
36322
36149
  fromChain?.chainId,
36323
36150
  toChain?.chainId,
36324
36151
  toToken?.address,
36325
36152
  fromToken?.address,
36326
36153
  fromPrice,
36327
36154
  config.slippage,
36155
+ config.enableGetGasOnDestination,
36328
36156
  sourceUserAddress,
36329
36157
  config.degenMode,
36330
36158
  destinationAddress,
@@ -36596,6 +36424,35 @@ const useAvatar = (seed = zeroAddress) => {
36596
36424
  return avatar || "";
36597
36425
  };
36598
36426
 
36427
+ const useUserParams = () => {
36428
+ const enableGetGasOnDestination = useConfigStore((state) => state.config.enableGetGasOnDestination);
36429
+ const { fromToken, toToken, toChain, fromChain } = useSwap();
36430
+ // =============
36431
+ // GAS
36432
+ // =============
36433
+ const getGasOnDestSupportedForThisRoute = useMemo(() =>
36434
+ // Not supporting get gas on dest for same chains
36435
+ fromChain?.chainId !== toChain?.chainId &&
36436
+ // If the destination chain is cosmos, we don't support getting gas there
36437
+ toChain?.chainType !== ChainType.COSMOS &&
36438
+ // Not supporting get gas on dest for same tokens (bridge)
36439
+ ((fromToken?.subGraphIds?.some((sgi) => !!toToken?.subGraphIds?.includes(sgi)) &&
36440
+ toToken?.subGraphIds?.some((sgi) => !!fromToken?.subGraphIds?.includes(sgi))) ||
36441
+ // Except for uusdc -> uusdc
36442
+ (fromToken?.subGraphIds?.includes("uusdc") &&
36443
+ toToken?.subGraphIds?.includes("uusdc"))), [
36444
+ fromChain?.chainId,
36445
+ fromToken?.subGraphIds,
36446
+ toChain?.chainId,
36447
+ toToken?.subGraphIds,
36448
+ toChain?.chainType,
36449
+ ]);
36450
+ return {
36451
+ gasEnabled: enableGetGasOnDestination && getGasOnDestSupportedForThisRoute,
36452
+ getGasOnDestSupportedForThisRoute,
36453
+ };
36454
+ };
36455
+
36599
36456
  const useAddToken = (chainToCompare, tokenToCompare) => {
36600
36457
  const { chain: currentEvmChain } = useAccount();
36601
36458
  const { connector } = useAccount();
@@ -37023,5 +36880,5 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37023
36880
  React.createElement(CosmosProvider, null, children)))))))))) : (placeholder);
37024
36881
  };
37025
36882
 
37026
- export { useSwap as $, AxelarStatusResponseType as A, useHederaTokenAssociations as B, CHAIN_IDS as C, DEFAULT_LOCALE as D, useKeyboardNavigation as E, useSquidQueryClient as F, useSquid as G, HistoryTxType as H, useStellarAccountActivation as I, useAddressBookStore as J, useAssetsColorsStore as K, useFavoriteTokensStore as L, useHistoryStore as M, Nr as N, useSendTransactionStore as O, useConfigStore as P, QueryKeys as Q, useSquidStore as R, SquidStatusErrorType as S, TransactionErrorType as T, useSwapRoutePersistStore as U, useTransactionStore as V, Wo as W, XamanXrplNetwork as X, ConnectingWalletStatus as Y, useWalletStore as Z, useDepositAddress as _, WindowWalletFlag as a, getXummClient as a$, useAllConnectedWalletBalances as a0, useAllTokensWithBalanceForChainType as a1, useCosmosBalance as a2, useEvmBalance as a3, useMultiChainBalance as a4, useMultipleTokenPrices as a5, useBitcoinNativeBalance as a6, useCosmosNativeBalance as a7, useEvmNativeBalance as a8, useNativeBalance as a9, useAddToken as aA, useAutoConnect as aB, useEnsDataForAddress as aC, useEnsSearch as aD, useGnosisContext as aE, useIsSameAddressAndGnosisContext as aF, useIntegratorContext as aG, useMultiChainWallet as aH, useSigner as aI, useWallet as aJ, useWallets as aK, useXrplTrustLine as aL, TX_STATUS_CONSTANTS as aM, FINAL_TRANSACTION_STATUSES as aN, useGetFiatQuote as aO, useGetOnRampConfig as aP, useExecuteFiatQuote as aQ, useFiatOnRampTxStatus as aR, useFiatTransactions as aS, useCurrencyDetails as aT, useCountryDetails as aU, useAvailableQuotes as aV, useRecommendedQuote as aW, useGetOnrampPaymentTypes as aX, useSuggestedFiatAmounts as aY, SquidProvider as aZ, EnsService as a_, useSolanaNativeBalance as aa, useStellarNativeBalance as ab, useSuiNativeBalance as ac, useXrplNativeBalance as ad, useNativeTokenForChain as ae, useSingleTokenPrice as af, useSourceChainGasToken as ag, useSquidTokens as ah, useHistoricalData as ai, useTokensData as aj, useEstimateSendTransaction as ak, useSendTransaction as al, useSendTransactionGas as am, useAllTransactionsStatus as an, useApproval as ao, useEstimate as ap, useEstimatePriceImpact as aq, useExecuteTransaction as ar, useGetRoute as as, useGetRouteWrapper as at, useRouteWarnings as au, useSendTransactionStatus as av, useSwapTransactionStatus as aw, useAvatar as ax, useHistory as ay, useDebouncedValue as az, chainTypeToZeroAddressMap as b, adaptiveRound as b$, isXamanXAppContext as b0, getQueryHeaders as b1, getStatusCode as b2, is404Error as b3, assetsBaseUrl as b4, shareSubgraphId as b5, sortTokensBySharedSubgraphIds as b6, getSupportedChainIdsForDirection as b7, filterChains as b8, filterTokens as b9, getCosmosKey as bA, getKeysSettled as bB, getAllKeysForSupportedCosmosChains as bC, isCosmosAddressValid as bD, getCosmosSigningClient as bE, getCosmosChainInfosObject as bF, connectCosmosWallet as bG, isFallbackAddressNeeded as bH, suggestChainOrThrow as bI, normalizeError as bJ, transactionErrorCode as bK, isUserRejectionError as bL, getTransactionError as bM, handleTransactionErrorEvents as bN, isSwapRouteError as bO, isStatusError as bP, createQuoteRequestParamsHash as bQ, WidgetEvents as bR, EvmNetworkNotSupportedErrorCode as bS, addEthereumChain as bT, parseEvmAddress as bU, formatEvmWallet as bV, filterWagmiConnector as bW, waitForReceiptWithRetry as bX, getUserCountry as bY, getCountryData as bZ, getCurrencyData as b_, getTokenImage as ba, getNewSwapParamsFromInput as bb, sortAllTokens as bc, findToken as bd, findNativeToken as be, normalizeIbcAddress as bf, groupTokensBySymbol as bg, groupTokensByChainId as bh, filterViewableTokens as bi, getSecretNetworkBalances as bj, getTokenAssetsKey as bk, fetchAssetsColors as bl, initializeSquidWithAssetsColors as bm, isEmptyObject as bn, normalizeTokenSymbol as bo, areTokenSymbolsCompatible as bp, isEvmosChain as bq, getConfigWithDefaults as br, randomIntFromInterval as bs, getTokensForChain as bt, getFirstAvailableChainId as bu, fetchHighestBalanceToken as bv, getInitialOrDefaultTokenAddressForChain as bw, getInitialTokenAddressForChain as bx, filterTokensForDestination as by, getInitialChainIdFromConfig as bz, chainTypeToNativeTokenAddressMap as c, addTokenToWallet as c$, getSuggestedAmountsForCurrency as c0, HederaExtensionHelper as c1, convertHederaAccountIdToEvmAddress as c2, convertEvmAddressToHederaAccountId as c3, scaleHbarToWei as c4, scaleWeiToHbar as c5, parseToBigInt as c6, roundNumericValue as c7, formatUnitsRounded as c8, formatTokenAmount as c9, isChainflipBridgeTransaction as cA, isOnChainTxData as cB, isDepositWithSignatureTxData as cC, getHistoryTransactionId as cD, getStepStatuses as cE, getHalfSuccessState as cF, getStepsInfos as cG, getSwapTxStatusRefetchInterval as cH, getSendTxStatusRefetchInterval as cI, chainflipMultihopBridgeType as cJ, getBridgeType as cK, getTransactionStatus as cL, getTransactionEndStatus as cM, isHistoryTransactionPending as cN, isHistoryTransactionFailed as cO, isHistoryTransactionWarning as cP, isHistoryTransactionEnded as cQ, formatHash as cR, isWalletAddressValid as cS, redirectToExtensionsStore as cT, accessProperty as cU, populateWallets as cV, getDefaultChain as cW, sortWallets as cX, areSameAddress as cY, sortAddressBook as cZ, calculateTotalUsdBalanceUSD as c_, formatUsdAmount as ca, trimExtraDecimals as cb, getNumericValue as cc, cleanAmount as cd, convertTokenAmountToUSD as ce, convertUSDToTokenAmount as cf, calculateTotal24hChange as cg, getRouteExpiry as ch, searchTokens as ci, filterSolanaWallets as cj, isSolanaAddressValid as ck, executeSolanaSwap as cl, executeSolanaTransfer as cm, formatTransactionHistoryDate as cn, getAxelarExplorerTxUrl as co, getSourceExplorerTxUrl as cp, getMainExplorerUrl as cq, formatDistance as cr, formatSeconds as cs, formatSwapTxStatusResponseForStorage as ct, simplifyRouteAction as cu, fetchSwapTransactionStatus as cv, compareTransactionIds as cw, isCoralBridgeAction as cx, sleep as cy, isDepositRoute as cz, definedInWindow as d, isEvmChainNotSupportedError as d0, getWalletSupportedChainTypes as d1, getConnectorForChainType as d2, walletSupportsChainType as d3, connectWallet as d4, cancelConnectWallet as d5, isProblematicConnector as d6, mergeWallets as d7, isXionSmartContractAddress as d8, isXrplAddressValid as d9, buildXrplTrustSetTx as da, getXrplNetwork as db, parseXrplPaymentTx as dc, er as e, formatBNToReadable as f, DEFAULT_ROUTE_REFETCH_INTERVAL as g, destinationAddressResetValue as h, fallbackAddressResetValue as i, nativeCosmosTokenAddress as j, nativeEvmTokenAddress as k, nativeSolanaTokenAddress as l, nativeStellarTokenAddress as m, nativeBitcoinTokenAddress as n, nativeSuiTokenAddress as o, nativeXrplTokenAddress as p, CosmosProvider as q, SendTransactionStatus as r, TransactionStatus as s, useTrackSearchEmpty as t, useCosmosContext as u, useSquidChains as v, walletIconBaseUrl as w, useClient as x, useCosmosForChain as y, useHederaAccountActivation as z };
37027
- //# sourceMappingURL=index-B4aeecpP.js.map
36883
+ export { useSwap as $, AxelarStatusResponseType as A, useKeyboardNavigation as B, CHAIN_IDS as C, DEFAULT_LOCALE as D, useSquidQueryClient as E, useSquid as F, useStellarAccountActivation as G, HistoryTxType as H, useHederaAccountActivation as I, useAddressBookStore as J, useAssetsColorsStore as K, useFavoriteTokensStore as L, useHistoryStore as M, Nr as N, useSendTransactionStore as O, useConfigStore as P, QueryKeys as Q, useSquidStore as R, SquidStatusErrorType as S, TransactionErrorType as T, useSwapRoutePersistStore as U, useTransactionStore as V, Wo as W, XamanXrplNetwork as X, ConnectingWalletStatus as Y, useWalletStore as Z, useDepositAddress as _, WindowWalletFlag as a, getXummClient as a$, useAllConnectedWalletBalances as a0, useAllTokensWithBalanceForChainType as a1, useCosmosBalance as a2, useEvmBalance as a3, useMultiChainBalance as a4, useMultipleTokenPrices as a5, useBitcoinNativeBalance as a6, useCosmosNativeBalance as a7, useEvmNativeBalance as a8, useNativeBalance as a9, useAddToken as aA, useAutoConnect as aB, useEnsDataForAddress as aC, useEnsSearch as aD, useGnosisContext as aE, useIsSameAddressAndGnosisContext as aF, useIntegratorContext as aG, useMultiChainWallet as aH, useSigner as aI, useWallet as aJ, useWallets as aK, useXrplTrustLine as aL, TX_STATUS_CONSTANTS as aM, FINAL_TRANSACTION_STATUSES as aN, useGetFiatQuote as aO, useGetOnRampConfig as aP, useExecuteFiatQuote as aQ, useFiatOnRampTxStatus as aR, useFiatTransactions as aS, useCurrencyDetails as aT, useCountryDetails as aU, useAvailableQuotes as aV, useRecommendedQuote as aW, useGetOnrampPaymentTypes as aX, useSuggestedFiatAmounts as aY, SquidProvider as aZ, EnsService as a_, useSolanaNativeBalance as aa, useStellarNativeBalance as ab, useSuiNativeBalance as ac, useXrplNativeBalance as ad, useNativeTokenForChain as ae, useSingleTokenPrice as af, useSquidTokens as ag, useHistoricalData as ah, useTokensData as ai, useEstimateSendTransaction as aj, useSendTransaction as ak, useSendTransactionGas as al, useAllTransactionsStatus as am, useApproval as an, useEstimate as ao, useEstimatePriceImpact as ap, useExecuteTransaction as aq, useGetRoute as ar, useGetRouteWrapper as as, useRouteWarnings as at, useSendTransactionStatus as au, useSwapTransactionStatus as av, useAvatar as aw, useHistory as ax, useUserParams as ay, useDebouncedValue as az, chainTypeToZeroAddressMap as b, adaptiveRound as b$, isXamanXAppContext as b0, getQueryHeaders as b1, getStatusCode as b2, is404Error as b3, assetsBaseUrl as b4, shareSubgraphId as b5, sortTokensBySharedSubgraphIds as b6, getSupportedChainIdsForDirection as b7, filterChains as b8, filterTokens as b9, getCosmosKey as bA, getKeysSettled as bB, getAllKeysForSupportedCosmosChains as bC, isCosmosAddressValid as bD, getCosmosSigningClient as bE, getCosmosChainInfosObject as bF, connectCosmosWallet as bG, isFallbackAddressNeeded as bH, suggestChainOrThrow as bI, normalizeError as bJ, transactionErrorCode as bK, isUserRejectionError as bL, getTransactionError as bM, handleTransactionErrorEvents as bN, isSwapRouteError as bO, isStatusError as bP, createQuoteRequestParamsHash as bQ, WidgetEvents as bR, EvmNetworkNotSupportedErrorCode as bS, addEthereumChain as bT, parseEvmAddress as bU, formatEvmWallet as bV, filterWagmiConnector as bW, waitForReceiptWithRetry as bX, getUserCountry as bY, getCountryData as bZ, getCurrencyData as b_, getTokenImage as ba, getNewSwapParamsFromInput as bb, sortAllTokens as bc, findToken as bd, findNativeToken as be, normalizeIbcAddress as bf, groupTokensBySymbol as bg, groupTokensByChainId as bh, filterViewableTokens as bi, getSecretNetworkBalances as bj, getTokenAssetsKey as bk, fetchAssetsColors as bl, initializeSquidWithAssetsColors as bm, isEmptyObject as bn, normalizeTokenSymbol as bo, areTokenSymbolsCompatible as bp, isEvmosChain as bq, getConfigWithDefaults as br, randomIntFromInterval as bs, getTokensForChain as bt, getFirstAvailableChainId as bu, fetchHighestBalanceToken as bv, getInitialOrDefaultTokenAddressForChain as bw, getInitialTokenAddressForChain as bx, filterTokensForDestination as by, getInitialChainIdFromConfig as bz, chainTypeToNativeTokenAddressMap as c, isEvmChainNotSupportedError as c$, getSuggestedAmountsForCurrency as c0, HederaExtensionHelper as c1, convertHederaAccountIdToEvmAddress as c2, convertEvmAddressToHederaAccountId as c3, scaleHbarToWei as c4, scaleWeiToHbar as c5, parseToBigInt as c6, roundNumericValue as c7, formatUnitsRounded as c8, formatTokenAmount as c9, isChainflipBridgeTransaction as cA, isOnChainTxData as cB, getHistoryTransactionId as cC, getStepStatuses as cD, getHalfSuccessState as cE, getStepsInfos as cF, getSwapTxStatusRefetchInterval as cG, getSendTxStatusRefetchInterval as cH, chainflipMultihopBridgeType as cI, getBridgeType as cJ, getTransactionStatus as cK, getTransactionEndStatus as cL, isHistoryTransactionPending as cM, isHistoryTransactionFailed as cN, isHistoryTransactionWarning as cO, isHistoryTransactionEnded as cP, formatHash as cQ, isWalletAddressValid as cR, redirectToExtensionsStore as cS, accessProperty as cT, populateWallets as cU, getDefaultChain as cV, sortWallets as cW, areSameAddress as cX, sortAddressBook as cY, calculateTotalUsdBalanceUSD as cZ, addTokenToWallet as c_, formatUsdAmount as ca, trimExtraDecimals as cb, getNumericValue as cc, cleanAmount as cd, convertTokenAmountToUSD as ce, convertUSDToTokenAmount as cf, calculateTotal24hChange as cg, getRouteExpiry as ch, searchTokens as ci, filterSolanaWallets as cj, isSolanaAddressValid as ck, executeSolanaSwap as cl, executeSolanaTransfer as cm, formatTransactionHistoryDate as cn, getAxelarExplorerTxUrl as co, getSourceExplorerTxUrl as cp, getMainExplorerUrl as cq, formatDistance as cr, formatSeconds as cs, formatSwapTxStatusResponseForStorage as ct, simplifyRouteAction as cu, fetchSwapTransactionStatus as cv, compareTransactionIds as cw, isCoralBridgeAction as cx, sleep as cy, isDepositRoute as cz, definedInWindow as d, getWalletSupportedChainTypes as d0, getConnectorForChainType as d1, walletSupportsChainType as d2, connectWallet as d3, cancelConnectWallet as d4, isProblematicConnector as d5, mergeWallets as d6, isXionSmartContractAddress as d7, isXrplAddressValid as d8, buildXrplTrustSetTx as d9, getXrplNetwork as da, parseXrplPaymentTx as db, er as e, formatBNToReadable as f, DEFAULT_ROUTE_REFETCH_INTERVAL as g, destinationAddressResetValue as h, fallbackAddressResetValue as i, nativeCosmosTokenAddress as j, nativeEvmTokenAddress as k, nativeSolanaTokenAddress as l, nativeStellarTokenAddress as m, nativeBitcoinTokenAddress as n, nativeSuiTokenAddress as o, nativeXrplTokenAddress as p, CosmosProvider as q, SendTransactionStatus as r, TransactionStatus as s, useTrackSearchEmpty as t, useCosmosContext as u, useSquidChains as v, walletIconBaseUrl as w, useClient as x, useCosmosForChain as y, useHederaTokenAssociations as z };
36884
+ //# sourceMappingURL=index-BGVXRZI6.js.map