@0xsquid/react-hooks 8.4.1-beta-interactive-to-amount.0 → 8.4.1-beta-tempo.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 (39) hide show
  1. package/dist/core/constants.d.ts +3 -0
  2. package/dist/core/queries/queries-keys.d.ts +1 -1
  3. package/dist/core/types/config.d.ts +0 -1
  4. package/dist/core/types/route.d.ts +1 -1
  5. package/dist/hooks/index.d.ts +2 -2
  6. package/dist/hooks/store/useSquidStore.d.ts +1 -2
  7. package/dist/hooks/swap/useSwap.d.ts +2 -4
  8. package/dist/hooks/tokens/useSourceChainGasToken.d.ts +11 -0
  9. package/dist/hooks/transaction/send/useEstimateSendTransactionGas.d.ts +6 -2
  10. package/dist/hooks/transaction/useEstimate.d.ts +5 -11
  11. package/dist/hooks/transaction/useGetRoute.d.ts +0 -1
  12. package/dist/hooks/transaction/useTempoFeeCheck.d.ts +11 -0
  13. package/dist/{index-DnkELFs9.js → index-B4aeecpP.js} +1319 -1203
  14. package/dist/index-B4aeecpP.js.map +1 -0
  15. package/dist/{index-Bg7CS2Uo.js → index-CaI-xWCW.js} +1316 -1200
  16. package/dist/index-CaI-xWCW.js.map +1 -0
  17. package/dist/{index.es-tWag56u3.js → index.es-BXf9jwuI.js} +3 -3
  18. package/dist/{index.es-tWag56u3.js.map → index.es-BXf9jwuI.js.map} +1 -1
  19. package/dist/{index.es-BQGUcysL.js → index.es-DAfqL2H0.js} +3 -3
  20. package/dist/{index.es-BQGUcysL.js.map → index.es-DAfqL2H0.js.map} +1 -1
  21. package/dist/index.esm.js +2 -2
  22. package/dist/index.js +3 -3
  23. package/dist/{secretService-Bs5SPC6i.js → secretService-CIYxEkTN.js} +3 -3
  24. package/dist/{secretService-Bs5SPC6i.js.map → secretService-CIYxEkTN.js.map} +1 -1
  25. package/dist/{secretService-BXleHutG.js → secretService-Cld4gYfG.js} +3 -3
  26. package/dist/{secretService-BXleHutG.js.map → secretService-Cld4gYfG.js.map} +1 -1
  27. package/dist/services/internal/assetsService.d.ts +2 -2
  28. package/dist/services/internal/estimateService.d.ts +13 -27
  29. package/dist/services/internal/tempoService.d.ts +82 -0
  30. package/dist/{stellarService.client-li6iEHAu.js → stellarService.client-COeQeah_.js} +3 -3
  31. package/dist/{stellarService.client-li6iEHAu.js.map → stellarService.client-COeQeah_.js.map} +1 -1
  32. package/dist/{stellarService.client-TTYw1-aB.js → stellarService.client-ocLzRIB4.js} +3 -3
  33. package/dist/{stellarService.client-TTYw1-aB.js.map → stellarService.client-ocLzRIB4.js.map} +1 -1
  34. package/dist/tests/networkGasToken.test.d.ts +1 -0
  35. package/dist/tests/tempoService.test.d.ts +1 -0
  36. package/package.json +1 -1
  37. package/dist/hooks/user/useUserParams.d.ts +0 -4
  38. package/dist/index-Bg7CS2Uo.js.map +0 -1
  39. package/dist/index-DnkELFs9.js.map +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, getAddress, defineChain, encodeFunctionData, erc20Abi } from 'viem';
2
+ import { zeroAddress as zeroAddress$1, parseUnits, formatUnits, isAddress, SwitchChainError, UserRejectedRequestError, erc20Abi, getAddress, defineChain, encodeFunctionData } 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, BrowserProvider, JsonRpcSigner, JsonRpcProvider, ethers, Interface, Contract as Contract$1, isError } from 'ethers';
18
+ import { CloudflareProvider, JsonRpcProvider, ethers, Interface, BrowserProvider, JsonRpcSigner, 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, createConfig, http, useWalletClient, usePublicClient, useBalance, useReadContract, WagmiProvider } from 'wagmi';
25
+ import { useAccount, useConnectors, useConnect, useDisconnect, useSwitchChain, useBalance, useReadContract, createConfig, http, useWalletClient, usePublicClient, 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';
30
29
  import { StargateClient, SigningStargateClient } from '@cosmjs/stargate';
31
30
  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,6 +124,9 @@ const CHAIN_IDS = {
124
124
  SONEIUM: "1868",
125
125
  PEAQ: "3338",
126
126
  HEDERA: "295",
127
+ MANTRA: "5888",
128
+ CITREA: "4114",
129
+ TEMPO: "4217",
127
130
  // others
128
131
  BITCOIN: "bitcoin",
129
132
  SOLANA: "solana-mainnet-beta",
@@ -22285,17 +22288,15 @@ const keys = () => ({
22285
22288
  // ============
22286
22289
  // Transactions
22287
22290
  // ============
22288
- transaction: (fromChainId, toChainId, toTokenAddress, fromTokenAddress, fromAmount, toAmount, slippage, getGasOnDestination, sourceUserAddress, degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChainType, preHook, postHook, overrideGasRefundAddress) => [
22291
+ transaction: (fromChainId, toChainId, toTokenAddress, fromTokenAddress, price, slippage, sourceUserAddress, degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChainType, preHook, postHook, overrideGasRefundAddress) => [
22289
22292
  ...keys().transactions(),
22290
22293
  QueryKeys.Transaction,
22291
22294
  fromChainId,
22292
22295
  toChainId,
22293
22296
  toTokenAddress,
22294
22297
  fromTokenAddress,
22295
- fromAmount,
22296
- toAmount,
22298
+ price,
22297
22299
  slippage,
22298
- getGasOnDestination,
22299
22300
  sourceUserAddress,
22300
22301
  degenMode,
22301
22302
  destinationAddress,
@@ -22456,7 +22457,6 @@ const getConfigWithDefaults = (config) => {
22456
22457
  integratorId: get$2(config, "integratorId", defaultConfigValues.integratorId),
22457
22458
  slippage: get$2(config, "slippage", defaultConfigValues.slippage),
22458
22459
  collectFees: get$2(config, "collectFees", defaultConfigValues.collectFees),
22459
- enableGetGasOnDestination: get$2(config, "enableGetGasOnDestination", defaultConfigValues.enableGetGasOnDestination),
22460
22460
  apiUrl: get$2(config, "apiUrl", defaultConfigValues.apiUrl),
22461
22461
  priceImpactWarnings: get$2(config, "priceImpactWarnings", defaultConfigValues.priceImpactWarnings),
22462
22462
  initialAssets: get$2(config, "initialAssets", defaultConfigValues.initialAssets),
@@ -22946,8 +22946,8 @@ const sortAllTokens = (tokenA, tokenB) => {
22946
22946
  return 0;
22947
22947
  };
22948
22948
  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);
22949
+ const findNativeToken = (tokens, chain) => tokens.find((t) => t.symbol.toUpperCase() === chain.nativeCurrency.symbol.toUpperCase() &&
22950
+ t.chainId == chain.chainId);
22951
22951
  const normalizeIbcAddress = (address) => {
22952
22952
  if (!address.toLowerCase().startsWith("ibc/")) {
22953
22953
  return address;
@@ -23158,7 +23158,7 @@ const filterViewableTokens = (tokens, config, direction) => {
23158
23158
  };
23159
23159
  const getSecretNetworkBalances = async (chainData, cosmosAddress, squidTokens, keplrTypeWallet) => {
23160
23160
  const squidSecretTokens = squidTokens.filter((t) => t.chainId === CHAIN_IDS.SECRET);
23161
- const { fetchAllSecretBalances } = await import('./secretService-Bs5SPC6i.js');
23161
+ const { fetchAllSecretBalances } = await import('./secretService-CIYxEkTN.js');
23162
23162
  return fetchAllSecretBalances(chainData, cosmosAddress, squidSecretTokens, keplrTypeWallet);
23163
23163
  };
23164
23164
  function getTokenAssetsKey(token) {
@@ -24849,7 +24849,7 @@ class OnrampService {
24849
24849
  });
24850
24850
  return data;
24851
24851
  }
24852
- async getConfiguration({ chains, tokens, }) {
24852
+ async getConfiguration({ chains: _, tokens, }) {
24853
24853
  const { data } = await axios.get(`${this.baseUrl}/config`);
24854
24854
  // Filter supportedCryptos to only include tokens that match our provided tokens
24855
24855
  const filteredCryptos = data.supportedCryptos.filter((supportedCrypto) => tokens.some((token) => token.address.toLowerCase() ===
@@ -25015,7 +25015,10 @@ const useConfigStore = create(() => ({
25015
25015
  isInitialized: false,
25016
25016
  }));
25017
25017
  const useTransactionStore = create((set, get) => ({
25018
+ fromPrice: undefined,
25019
+ txLocalId: undefined,
25018
25020
  transactions: {},
25021
+ currentTransaction: undefined,
25019
25022
  setTransactionState(txId, tx) {
25020
25023
  if (!txId)
25021
25024
  return;
@@ -26471,7 +26474,7 @@ function useStellarWallets() {
26471
26474
  try {
26472
26475
  const { allowAllModules: initializeAllModules } = await import('@creit.tech/stellar-wallets-kit');
26473
26476
  const { LedgerModule } = await import('@creit.tech/stellar-wallets-kit/modules/ledger.module');
26474
- const { formatStellarWallet } = await import('./stellarService.client-TTYw1-aB.js');
26477
+ const { formatStellarWallet } = await import('./stellarService.client-ocLzRIB4.js');
26475
26478
  const modules = [...initializeAllModules(), new LedgerModule()];
26476
26479
  const promises = modules.map(async (module) => {
26477
26480
  const isAvailable = await module.isAvailable();
@@ -27370,8 +27373,7 @@ const useMultiChainWallet = (chain) => {
27370
27373
 
27371
27374
  const useSwap = () => {
27372
27375
  const { initialAssets, defaultTokensPerChain, disabledChains, availableChains, } = useConfigStore((state) => state.config);
27373
- const fromAmount = useTransactionStore((state) => state.fromAmount);
27374
- const toAmount = useTransactionStore((state) => state.toAmount);
27376
+ const fromPrice = useTransactionStore((state) => state.fromPrice);
27375
27377
  const { swapRoute } = useSwapRoutePersistStore();
27376
27378
  const { tokens } = useSquidTokens();
27377
27379
  const queryClient = useQueryClient();
@@ -27429,17 +27431,8 @@ const useSwap = () => {
27429
27431
  }),
27430
27432
  };
27431
27433
  }, [destAddressData, destAddressEnsData.data, toChain?.chainType]);
27432
- const fromAmountChanged = useCallback((amount) => {
27433
- useTransactionStore.setState({
27434
- fromAmount: amount || undefined,
27435
- toAmount: undefined,
27436
- });
27437
- }, []);
27438
- const toAmountChanged = useCallback((amount) => {
27439
- useTransactionStore.setState({
27440
- toAmount: amount || undefined,
27441
- fromAmount: undefined,
27442
- });
27434
+ const fromPriceChanged = useCallback((price) => {
27435
+ useTransactionStore.setState({ fromPrice: price || undefined });
27443
27436
  }, []);
27444
27437
  /**
27445
27438
  * When user changes something from the SwapView
@@ -27580,10 +27573,8 @@ const useSwap = () => {
27580
27573
  tokenItems,
27581
27574
  onSwapChange,
27582
27575
  invertSwaps,
27583
- fromAmount,
27584
- toAmount,
27585
- fromAmountChanged,
27586
- toAmountChanged,
27576
+ fromPrice,
27577
+ fromPriceChanged,
27587
27578
  toToken,
27588
27579
  fromToken,
27589
27580
  fromChain,
@@ -27790,579 +27781,309 @@ function useTrackSearchEmpty({ searchQuery, resultsLength, context, debounceMs =
27790
27781
  }, [context, debounceMs, resultsLength, searchQuery]);
27791
27782
  }
27792
27783
 
27793
- var hrc20 = [
27794
- {
27795
- inputs: [
27796
- ],
27797
- name: "associate",
27798
- outputs: [
27799
- {
27800
- internalType: "uint256",
27801
- name: "responseCode",
27802
- type: "uint256"
27803
- }
27804
- ],
27805
- stateMutability: "nonpayable",
27806
- type: "function"
27807
- }
27808
- ];
27809
-
27810
- /**
27811
- * Client for interacting with the Hedera Mirrornode API.
27812
- *
27813
- * @docs https://mainnet.mirrornode.hedera.com/api/v1/docs
27814
- */
27815
- class HederaApiClient {
27816
- apiUrl;
27817
- constructor(apiUrl) {
27818
- this.apiUrl = apiUrl;
27819
- }
27820
- async isTokenAssociated({ address, token, }) {
27821
- const accountInfo = await this.getAccountInfo(address);
27822
- // Unlimited auto associations
27823
- if (accountInfo.max_automatic_token_associations === -1) {
27824
- return true;
27825
- }
27826
- // If there's no unlimited auto-associations, we need to check if the token is already associated.
27827
- const { tokens: accountTokens } = await this.getAccountTokens(address);
27828
- const tokenId = convertEvmAddressToHederaAccountId(token.address);
27829
- if (accountTokens.some((t) => t.token_id === tokenId)) {
27830
- // Token is already associated
27831
- return true;
27832
- }
27833
- // Finally, if not auto-associated, check if there is an available auto-association slot
27834
- const autoAssociatedTokens = accountTokens.filter((t) => t.automatic_association);
27835
- const remainingAutoAssociations = accountInfo.max_automatic_token_associations -
27836
- autoAssociatedTokens.length;
27837
- return remainingAutoAssociations > 0;
27784
+ class StellarRpcClient {
27785
+ server;
27786
+ constructor(rpcUrl) {
27787
+ this.server = new rpc.Server(rpcUrl);
27838
27788
  }
27839
- async getAccountInfo(address) {
27840
- const data = await this.fetch(`accounts/${address}`);
27841
- if (typeof data.max_automatic_token_associations !== "number") {
27842
- throw new Error("Invalid max_automatic_token_associations type, expected number");
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}`);
27843
27800
  }
27844
- if (typeof data.balance.balance !== "number") {
27845
- throw new Error("Invalid balance type, expected number");
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}`);
27846
27819
  }
27847
- if (!Array.isArray(data.balance.tokens)) {
27848
- throw new Error("Invalid tokens type, expected array");
27820
+ if ("result" in simulateTxResponse && simulateTxResponse.result != null) {
27821
+ const native = scValToNative(simulateTxResponse.result.retval);
27822
+ return native.toString();
27849
27823
  }
27850
- return data;
27824
+ throw new Error("Failed to fetch balance");
27851
27825
  }
27852
- async getAccountTokens(address) {
27853
- const data = await this.fetch(`accounts/${address}/tokens`);
27854
- if (!Array.isArray(data.tokens)) {
27855
- throw new Error("Invalid tokens type, expected array");
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
+ });
27843
+ }
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}`);
27856
27863
  }
27857
- const firstToken = data.tokens[0];
27858
- if (typeof firstToken?.automatic_association !== "boolean") {
27859
- throw new Error("Invalid automatic_association type, expected boolean");
27864
+ }
27865
+ async isAccountActivated(address) {
27866
+ try {
27867
+ await this.getAccount(address);
27868
+ return true;
27860
27869
  }
27861
- if (typeof firstToken?.token_id !== "string") {
27862
- throw new Error("Invalid token_id type, expected string");
27870
+ catch (error) {
27871
+ if (error?.message && error.message.includes("Account not found")) {
27872
+ return false;
27873
+ }
27874
+ throw error;
27863
27875
  }
27864
- return data;
27865
27876
  }
27866
- async fetch(path) {
27867
- const url = new URL(path, this.apiUrl);
27868
- const response = await fetch(url);
27869
- if (!response.ok) {
27870
- throw new Error(`Hedera API error: ${response.status}`);
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");
27871
27884
  }
27872
- return response.json();
27885
+ return transactionResponse;
27886
+ }
27887
+ async prepareTransaction(transaction) {
27888
+ return this.server.prepareTransaction(transaction);
27873
27889
  }
27874
27890
  }
27875
27891
 
27876
- hederaWalletConnect.type = "hederaWalletConnect";
27877
- /**
27878
- * Wagmi connector to interact with the Hedera EVM network via the WalletConnect protocol.
27879
- *
27880
- * The connector removes the need for a WalletConnect modal, and instead
27881
- * communicates with the provided `extension` by opening the extension popup
27882
- * for user interaction upon request.
27883
- */
27884
- function hederaWalletConnect(parameters) {
27885
- const { extension, ...restParameters } = parameters;
27886
- let provider_;
27887
- let providerPromise;
27888
- let connect;
27889
- let displayUri;
27890
- let sessionDelete;
27891
- let disconnect;
27892
- return createConnector((config) => ({
27893
- id: `hedera-wc-${extension.id}`,
27894
- name: extension.name,
27895
- icon: extension.icon,
27896
- type: hederaWalletConnect.type,
27897
- async setup() {
27898
- const provider = await this.getProvider().catch(() => null);
27899
- if (!provider)
27900
- return;
27901
- if (!connect) {
27902
- connect = this.onConnect.bind(this);
27903
- provider.on("connect", connect);
27904
- }
27905
- if (!sessionDelete) {
27906
- sessionDelete = this.onSessionDelete.bind(this);
27907
- provider.on("session_delete", sessionDelete);
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 };
27908
27947
  }
27909
- },
27910
- async connect(params = {}) {
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) {
27911
27958
  try {
27912
- const provider = await this.getProvider();
27913
- if (!provider)
27914
- throw new ProviderNotFoundError();
27915
- if (!displayUri) {
27916
- displayUri = this.onDisplayUri;
27917
- provider.on("display_uri", displayUri);
27918
- }
27919
- if (!provider.session) {
27920
- await provider.connect({
27921
- ...("pairingTopic" in params
27922
- ? { pairingTopic: params.pairingTopic }
27923
- : {}),
27924
- });
27925
- }
27926
- const accounts = (await provider.enable()).map((x) => getAddress(x));
27927
- const currentChainId = await this.getChainId();
27928
- if (displayUri) {
27929
- provider.removeListener("display_uri", displayUri);
27930
- displayUri = undefined;
27931
- }
27932
- if (connect) {
27933
- provider.removeListener("connect", connect);
27934
- connect = undefined;
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;
27935
27972
  }
27936
- if (!disconnect) {
27937
- disconnect = this.onDisconnect.bind(this);
27938
- provider.on("disconnect", disconnect);
27973
+ const status = response.meta?.TransactionResult;
27974
+ if (status === XrplTxStatus.SUCCESS) {
27975
+ return status;
27939
27976
  }
27940
- if (!sessionDelete) {
27941
- sessionDelete = this.onSessionDelete.bind(this);
27942
- provider.on("session_delete", sessionDelete);
27977
+ else {
27978
+ throw new Error(`Transaction failed with status: ${status}`);
27943
27979
  }
27944
- return { accounts, chainId: currentChainId };
27945
27980
  }
27946
27981
  catch (error) {
27947
- if (/(user rejected|connection request reset)/i.test(error?.message)) {
27948
- throw new UserRejectedRequestError(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;
27949
27990
  }
27950
27991
  throw error;
27951
27992
  }
27952
- },
27953
- async disconnect() {
27954
- const provider = await this.getProvider();
27955
- try {
27956
- await provider?.disconnect();
27957
- }
27958
- catch (error) {
27959
- if (!/No matching key/i.test(error.message))
27960
- throw error;
27961
- }
27962
- finally {
27963
- if (disconnect) {
27964
- provider?.removeListener("disconnect", disconnect);
27965
- disconnect = undefined;
27966
- }
27967
- if (!connect) {
27968
- connect = this.onConnect.bind(this);
27969
- provider?.on("connect", connect);
27970
- }
27971
- if (sessionDelete) {
27972
- provider?.removeListener("session_delete", sessionDelete);
27973
- sessionDelete = undefined;
27974
- }
27975
- }
27976
- },
27977
- async getAccounts() {
27978
- const provider = await this.getProvider();
27979
- return provider.accounts.map((x) => getAddress(x));
27980
- },
27981
- async getProvider() {
27982
- async function initProvider() {
27983
- const optionalChains = config.chains.map((x) => x.id);
27984
- if (!optionalChains.length)
27985
- return;
27986
- const { EthereumProvider } = await import('./index.es-tWag56u3.js');
27987
- const rawProvider = await EthereumProvider.init({
27988
- ...restParameters,
27989
- disableProviderPing: true,
27990
- optionalChains,
27991
- projectId: restParameters.projectId,
27992
- rpcMap: Object.fromEntries(config.chains.map((chain) => {
27993
- const [url] = extractRpcUrls({
27994
- chain,
27995
- transports: config.transports,
27996
- });
27997
- return [chain.id, url];
27998
- })),
27999
- showQrModal: false,
28000
- // We need to specify a custom storage prefix to avoid conflicts with Wagmi's walletConnect instance
28001
- // https://docs.reown.com/walletkit/web/usage#core-instance-sharing
28002
- customStoragePrefix: "squid-hedera",
28003
- });
28004
- const proxiedProvider = new Proxy(rawProvider, {
28005
- get(target, prop, receiver) {
28006
- if (prop === "request") {
28007
- return async (args) => {
28008
- const signingMethods = [
28009
- "eth_sendTransaction",
28010
- "eth_signTransaction",
28011
- ];
28012
- if (signingMethods.includes(args.method)) {
28013
- try {
28014
- HederaExtensionHelper.extensionOpen(extension.id);
28015
- }
28016
- catch { }
28017
- }
28018
- // forward request to original provider
28019
- return target.request(args);
28020
- };
28021
- }
28022
- // forward all other properties/methods
28023
- return Reflect.get(target, prop, receiver);
28024
- },
28025
- });
28026
- return proxiedProvider;
28027
- }
28028
- if (!provider_) {
28029
- if (!providerPromise)
28030
- providerPromise = initProvider();
28031
- provider_ = await providerPromise;
28032
- provider_?.events.setMaxListeners(Number.POSITIVE_INFINITY);
28033
- }
28034
- return provider_;
28035
- },
28036
- async getChainId() {
28037
- const provider = await this.getProvider();
28038
- return provider.chainId;
28039
- },
28040
- async isAuthorized() {
28041
- try {
28042
- const accounts = await this.getAccounts();
28043
- return accounts.length > 0;
28044
- }
28045
- catch {
28046
- return false;
28047
- }
28048
- },
28049
- onAccountsChanged(accounts) {
28050
- if (accounts.length === 0)
28051
- this.onDisconnect();
28052
- else
28053
- config.emitter.emit("change", {
28054
- accounts: accounts.map((x) => getAddress(x)),
28055
- });
28056
- },
28057
- onChainChanged(chain) {
28058
- const chainId = Number(chain);
28059
- config.emitter.emit("change", { chainId });
28060
- },
28061
- async onConnect(connectInfo) {
28062
- const chainId = Number(connectInfo.chainId);
28063
- const accounts = await this.getAccounts();
28064
- config.emitter.emit("connect", { accounts, chainId });
28065
- },
28066
- async onDisconnect() {
28067
- config.emitter.emit("disconnect");
28068
- const provider = await this.getProvider();
28069
- if (disconnect) {
28070
- provider.removeListener("disconnect", disconnect);
28071
- disconnect = undefined;
28072
- }
28073
- if (sessionDelete) {
28074
- provider.removeListener("session_delete", sessionDelete);
28075
- sessionDelete = undefined;
28076
- }
28077
- if (!connect) {
28078
- connect = this.onConnect.bind(this);
28079
- provider.on("connect", connect);
28080
- }
28081
- },
28082
- onDisplayUri(uri) {
28083
- config.emitter.emit("message", { type: "display_uri", data: uri });
28084
- HederaExtensionHelper.extensionConnect(extension.id, uri);
28085
- },
28086
- onSessionDelete() {
28087
- this.onDisconnect();
28088
- },
28089
- }));
28090
- }
28091
-
28092
- const createWagmiConfig = (squidChains, hederaExtensions) => {
28093
- const filteredEvmChains = squidChains.filter((chain) => chain.chainType === ChainType.EVM);
28094
- if (filteredEvmChains.length === 0) {
28095
- throw new Error("At least one chain is required");
27993
+ }
28096
27994
  }
28097
- const wagmiChains = filteredEvmChains.map((chain) => {
28098
- return defineChain({
28099
- id: Number(chain.chainId),
28100
- name: chain.networkName,
28101
- nativeCurrency: {
28102
- name: chain.nativeCurrency.name,
28103
- symbol: chain.nativeCurrency.symbol,
28104
- decimals: chain.nativeCurrency.decimals,
28105
- },
28106
- rpcUrls: {
28107
- public: {
28108
- http: [chain.rpc],
28109
- },
28110
- default: {
28111
- http: [chain.rpc],
28112
- },
27995
+ async getServerState() {
27996
+ return this.call("server_state", [{}]);
27997
+ }
27998
+ async getAccountInfo(address) {
27999
+ return this.call("account_info", [
28000
+ {
28001
+ account: address,
28002
+ ledger_index: "validated",
28113
28003
  },
28114
- });
28115
- });
28116
- const wcMetadata = {
28117
- url: SQUID_METADATA.url,
28118
- name: SQUID_METADATA.name,
28119
- icons: [SQUID_METADATA.icon],
28120
- description: SQUID_METADATA.description,
28121
- };
28122
- return createConfig({
28123
- chains: wagmiChains,
28124
- transports: Object.fromEntries(wagmiChains.map((chain) => [
28125
- chain.id,
28126
- http(chain.rpcUrls.public.http[0] ?? ""),
28127
- ])),
28128
- connectors: [
28129
- injected(),
28130
- safe({
28131
- allowedDomains: [/app.safe.global$/],
28132
- }),
28133
- metaMask({
28134
- dappMetadata: {
28135
- name: SQUID_METADATA.name,
28136
- url: SQUID_METADATA.url,
28137
- iconUrl: SQUID_METADATA.icon,
28138
- },
28139
- }),
28140
- coinbaseWallet({
28141
- appName: SQUID_METADATA.name,
28142
- appLogoUrl: SQUID_METADATA.icon,
28143
- }),
28144
- walletConnect({
28145
- projectId: WALLETCONNECT_PROJECT_ID,
28146
- metadata: wcMetadata,
28147
- }),
28148
- ...hederaExtensions.map((extension) => hederaWalletConnect({
28149
- projectId: WALLETCONNECT_PROJECT_ID,
28150
- metadata: wcMetadata,
28151
- extension,
28152
- })),
28153
- ],
28154
- });
28155
- };
28156
- // Taken from wagmi docs
28157
- // https://wagmi.sh/react/guides/ethers
28158
- function clientToSigner(client) {
28159
- const { account, chain, transport } = client;
28160
- if (!account || !chain || !transport) {
28161
- return undefined;
28004
+ ]);
28162
28005
  }
28163
- const network = {
28164
- chainId: chain.id,
28165
- name: chain.name,
28166
- ensAddress: chain.contracts?.ensRegistry?.address,
28167
- };
28168
- const provider = new BrowserProvider(transport, network);
28169
- const signer = new JsonRpcSigner(provider, account.address);
28170
- return signer;
28171
- }
28172
-
28173
- function useEvmSigner({ chainId }) {
28174
- const { connector } = useAccount();
28175
- const { data: client } = useWalletClient({ chainId, connector });
28176
- const signer = useMemo(() => (client ? clientToSigner(client) : undefined), [client]);
28177
- return { signer };
28178
- }
28179
- const useSigner = ({ chain }) => {
28180
- const evmChainId = chain?.chainType === ChainType.EVM ? Number(chain.chainId) : undefined;
28181
- // EVM and Cosmos need a different signer for each chain
28182
- // This is not the case for Solana or Bitcoin as there's only one chain in those ecosystems
28183
- const { signer: evmSigner } = useEvmSigner({ chainId: evmChainId });
28184
- const { signer: cosmosSigner } = useCosmosSigner({ chain });
28185
- const { signer: solanaSigner } = useSolanaContext();
28186
- const { signer: bitcoinSigner } = useBitcoinContext();
28187
- const { signer: suiSigner } = useSuiContext();
28188
- const { signer: xrplSigner } = useXrplContext();
28189
- const { signer: stellarSigner } = useStellarContext();
28190
- const isEvmSignerReady = !!evmSigner;
28191
- const isSolanaSignerReady = !!solanaSigner;
28192
- const isCosmosSignerReady = !!cosmosSigner;
28193
- const isBitcoinSignerReady = !!bitcoinSigner;
28194
- const isSuiSignerReady = !!suiSigner;
28195
- const isXrplSignerReady = !!xrplSigner;
28196
- const isStellarSignerReady = !!stellarSigner;
28197
- const isSignerReady = useMemo(() => {
28198
- if (!chain?.chainType)
28199
- return false;
28200
- switch (chain.chainType) {
28201
- case ChainType.EVM:
28202
- return isEvmSignerReady;
28203
- case ChainType.COSMOS:
28204
- return isCosmosSignerReady;
28205
- case ChainType.BTC:
28206
- return isBitcoinSignerReady;
28207
- case ChainType.SOLANA:
28208
- return isSolanaSignerReady;
28209
- case ChainType.SUI:
28210
- return isSuiSignerReady;
28211
- case ChainType.XRPL:
28212
- return isXrplSignerReady;
28213
- case ChainType.STELLAR:
28214
- return isStellarSignerReady;
28215
- }
28216
- }, [
28217
- chain?.chainType,
28218
- isEvmSignerReady,
28219
- isCosmosSignerReady,
28220
- isBitcoinSignerReady,
28221
- isSolanaSignerReady,
28222
- isSuiSignerReady,
28223
- isXrplSignerReady,
28224
- isStellarSignerReady,
28225
- ]);
28226
- return {
28227
- isSignerReady,
28228
- evmSigner,
28229
- cosmosSigner,
28230
- bitcoinSigner,
28231
- solanaSigner,
28232
- suiSigner,
28233
- xrplSigner,
28234
- stellarSigner,
28235
- };
28236
- };
28237
-
28238
- function useHederaTokenAssociations({ address, chain, token }) {
28239
- const publicClient = usePublicClient({
28240
- chainId: Number(CHAIN_IDS.HEDERA),
28241
- });
28242
- const { evmSigner } = useSigner({ chain });
28243
- const queryClient = useQueryClient();
28244
28006
  /**
28245
- * Creates a token association transaction where the destination account authorizes to receive the given token
28007
+ * Returns the balance of the user in the native XRP token
28008
+ * formatted as a string
28246
28009
  */
28247
- const associateToken = useMutation({
28248
- mutationFn: async () => {
28249
- try {
28250
- if (!evmSigner) {
28251
- throw new Error("EVM signer not found");
28252
- }
28253
- if (chain?.chainId !== CHAIN_IDS.HEDERA ||
28254
- token?.chainId !== CHAIN_IDS.HEDERA) {
28255
- throw new Error("Chain and token to associate must be on Hedera");
28256
- }
28257
- const tokenAddress = parseEvmAddress(token.address);
28258
- if (!tokenAddress) {
28259
- throw new Error("Invalid token address");
28260
- }
28261
- const userAddress = parseEvmAddress(address);
28262
- if (!userAddress) {
28263
- throw new Error("Invalid user address");
28264
- }
28265
- const encodedData = encodeFunctionData({
28266
- abi: hrc20,
28267
- functionName: "associate",
28268
- args: [],
28269
- });
28270
- const txRes = await evmSigner.sendTransaction({
28271
- data: encodedData,
28272
- to: tokenAddress,
28273
- chainId: chain.chainId,
28274
- });
28275
- const receipt = await txRes.wait();
28276
- if (receipt?.status !== 1) {
28277
- throw new Error(`Transaction failed with status: ${receipt?.status}`);
28278
- }
28279
- return true;
28280
- }
28281
- catch (error) {
28282
- console.error("Error associating Hedera token:", error);
28283
- return false;
28284
- }
28285
- },
28286
- async onSuccess() {
28287
- queryClient.refetchQueries({
28288
- queryKey: getPrefixKey(QueryKeys.IsHederaTokenAssociated),
28289
- });
28290
- },
28291
- });
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
+ }
28292
28023
  /**
28293
- * Checks if the destination account has associated the given token.
28294
- *
28295
- * Hedera requires accounts to associate a token before being able to receive it.
28296
- *
28297
- * Accounts which have max. associations set to -1 can receive any token without previous association
28024
+ * Returns the balance of the user in the given issued currency (e.g. RLUSD)
28025
+ * formatted as a string
28298
28026
  */
28299
- const isTokenAssociated = useQuery({
28300
- queryKey: keys().isHederaTokenAssociated(address, token?.chainId, token?.type, token?.address),
28301
- queryFn: async () => {
28302
- if (token?.chainId !== CHAIN_IDS.HEDERA) {
28303
- return true;
28304
- }
28305
- // The native HBAR token doesn't need an association
28306
- if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase()) {
28307
- return true;
28308
- }
28309
- if (!chain || !address || !publicClient) {
28310
- throw new Error("Missing required parameters");
28311
- }
28312
- // TODO: update types
28313
- const apiUrl = chain?.chainConfig?.hedera?.mirrorNodeUrl;
28314
- if (!apiUrl) {
28315
- throw new Error("Missing Hedera mirror node URL in chain config");
28316
- }
28317
- const hederaApiClient = new HederaApiClient(apiUrl);
28318
- return hederaApiClient.isTokenAssociated({
28319
- address,
28320
- token,
28321
- });
28322
- },
28323
- enabled: !!address && !!publicClient && token?.chainId === CHAIN_IDS.HEDERA,
28324
- });
28325
- return {
28326
- isTokenAssociated,
28327
- associateToken,
28328
- };
28329
- }
28330
-
28331
- const useKeyboardNavigation = ({ onEscape }) => {
28332
- const onKeyDown = useCallback((event) => {
28333
- if (event.key === "Escape") {
28334
- onEscape?.();
28335
- return;
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",
28037
+ },
28038
+ body: JSON.stringify({
28039
+ jsonrpc: "2.0",
28040
+ id: 1,
28041
+ method,
28042
+ params,
28043
+ }),
28044
+ });
28045
+ const data = await response.json();
28046
+ if (!data.result) {
28047
+ throw new Error(`Invalid response from RPC (${method})`);
28336
28048
  }
28337
- }, [onEscape]);
28338
- useEffect(() => {
28339
- document.addEventListener("keydown", onKeyDown, false);
28340
- return () => {
28341
- document.removeEventListener("keydown", onKeyDown, false);
28342
- };
28343
- }, [onKeyDown]);
28344
- };
28049
+ if ("error" in data.result) {
28050
+ throw new Error(`Error from RPC (${method}): ${data.result.error}`);
28051
+ }
28052
+ return data.result;
28053
+ }
28054
+ }
28345
28055
 
28346
- const useSquidQueryClient = () => {
28347
- const queryClient = useQueryClient();
28348
- const invalidateQueries = (key) => {
28349
- const prefixKey = getPrefixKey(key);
28350
- queryClient.invalidateQueries(prefixKey);
28351
- };
28352
- const refetchQueries = (key) => {
28353
- const prefixKey = getPrefixKey(key);
28354
- queryClient.refetchQueries(prefixKey);
28355
- };
28356
- const invalidateAndRefetchQueries = (key) => {
28357
- invalidateQueries(key);
28358
- refetchQueries(key);
28359
- };
28360
- return {
28361
- invalidateQueries,
28362
- refetchQueries,
28363
- invalidateAndRefetchQueries,
28364
- };
28365
- };
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;
28065
+ }
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,
28080
+ });
28081
+ case ChainType.XRPL:
28082
+ return new XrplRpcClient(chain.rpc);
28083
+ case ChainType.STELLAR:
28084
+ return new StellarRpcClient(chain.rpc);
28085
+ }
28086
+ }
28366
28087
 
28367
28088
  /**
28368
28089
  * The default multicall3 address
@@ -29378,372 +29099,6 @@ function timeout(ms, promise) {
29378
29099
  return Promise.race([promise, timeoutPromise]);
29379
29100
  }
29380
29101
 
29381
- class StellarRpcClient {
29382
- server;
29383
- constructor(rpcUrl) {
29384
- this.server = new rpc.Server(rpcUrl);
29385
- }
29386
- /**
29387
- * Returns the balance of a Stellar Contract Token. This is different from an Issued Token.
29388
- *
29389
- * With Contract Tokens, we need to call the .balance method on the token contract
29390
- * and simulate the transaction to get the balance.
29391
- */
29392
- async getBalance(userAddress, tokenAddress, chainId) {
29393
- const account = await this.server.getAccount(userAddress);
29394
- const network = getStellarNetwork(chainId);
29395
- if (network == null) {
29396
- throw new Error(`No Stellar network found for chainId ${chainId}`);
29397
- }
29398
- const txBuilder = new TransactionBuilder(account, {
29399
- fee: (BigInt(BASE_FEE) * BigInt(2)).toString(),
29400
- networkPassphrase: network,
29401
- });
29402
- const contract = new Contract(tokenAddress);
29403
- const tx = txBuilder
29404
- .addOperation(contract.call("balance", new Address(userAddress).toScVal()))
29405
- .setTimeout(TimeoutInfinite)
29406
- .build();
29407
- const simulateTxResponse = await this.server.simulateTransaction(tx);
29408
- if ("error" in simulateTxResponse) {
29409
- const isNoBalanceError = simulateTxResponse.error.includes("trying to get non-existing value for contract instance");
29410
- // If the error message indicates that the user has no balance just return 0
29411
- // We don't want to spam with this error as it's pretty common
29412
- if (isNoBalanceError) {
29413
- return "0";
29414
- }
29415
- throw new Error(`Failed to fetch balance. RPC response: ${simulateTxResponse.error}`);
29416
- }
29417
- if ("result" in simulateTxResponse && simulateTxResponse.result != null) {
29418
- const native = scValToNative(simulateTxResponse.result.retval);
29419
- return native.toString();
29420
- }
29421
- throw new Error("Failed to fetch balance");
29422
- }
29423
- async getAllBalances(userAddress, tokens) {
29424
- const balancePromises = tokens.map((token) => {
29425
- return this.getBalance(userAddress, token.address, token.chainId);
29426
- });
29427
- const results = await Promise.allSettled(balancePromises);
29428
- const balances = results.map((result) => {
29429
- if (result.status === "fulfilled") {
29430
- return result.value;
29431
- }
29432
- return "0";
29433
- });
29434
- return balances.map((balance, index) => {
29435
- return {
29436
- ...tokens[index],
29437
- balance,
29438
- };
29439
- });
29440
- }
29441
- /**
29442
- * Resolves when the transaction is confirmed, or fails after a timeout.
29443
- */
29444
- async waitForTransaction(txHash, { interval = 2_000, timeout = 40_000 } = {}) {
29445
- const startTime = Date.now();
29446
- while (true) {
29447
- const result = await this.server.getTransaction(txHash);
29448
- if (result.status === rpc.Api.GetTransactionStatus.NOT_FOUND) {
29449
- if (Date.now() - startTime > timeout) {
29450
- throw new Error(`Transaction ${txHash} not found within timeout`);
29451
- }
29452
- // eslint-disable-next-line @typescript-eslint/no-loop-func
29453
- await new Promise((res) => setTimeout(res, interval));
29454
- continue;
29455
- }
29456
- if (result.status === rpc.Api.GetTransactionStatus.SUCCESS) {
29457
- return result.status;
29458
- }
29459
- throw new Error(`Transaction failed with status: ${result.status}`);
29460
- }
29461
- }
29462
- async isAccountActivated(address) {
29463
- try {
29464
- await this.getAccount(address);
29465
- return true;
29466
- }
29467
- catch (error) {
29468
- if (error?.message && error.message.includes("Account not found")) {
29469
- return false;
29470
- }
29471
- throw error;
29472
- }
29473
- }
29474
- async getAccount(address) {
29475
- return this.server.getAccount(address);
29476
- }
29477
- async sendTransaction(transaction) {
29478
- const transactionResponse = await this.server.sendTransaction(transaction);
29479
- if (transactionResponse.status === "ERROR") {
29480
- throw new Error("Error sending transaction");
29481
- }
29482
- return transactionResponse;
29483
- }
29484
- async prepareTransaction(transaction) {
29485
- return this.server.prepareTransaction(transaction);
29486
- }
29487
- }
29488
-
29489
- class XrplRpcClient {
29490
- rpcUrl;
29491
- constructor(rpcUrl) {
29492
- this.rpcUrl = rpcUrl;
29493
- }
29494
- async getBalance(address, tokenAddress) {
29495
- if (tokenAddress.toLowerCase() === nativeXrplTokenAddress.toLowerCase()) {
29496
- return this.getNativeBalance(address);
29497
- }
29498
- return this.getIssuedCurrencyBalance(address, tokenAddress);
29499
- }
29500
- async getAllBalances(address) {
29501
- const [nativeBalance, trustLineBalances] = await Promise.all([
29502
- this.getNativeBalance(address),
29503
- this.getTrustLines(address),
29504
- ]);
29505
- return [
29506
- {
29507
- balance: nativeBalance,
29508
- address: nativeXrplTokenAddress,
29509
- },
29510
- ...trustLineBalances.lines.map((line) => ({
29511
- balance: line.balance,
29512
- address: `${line.currency}.${line.account}`,
29513
- })),
29514
- ];
29515
- }
29516
- async getTrustLines(address, issuer) {
29517
- return this.call("account_lines", [
29518
- {
29519
- account: address,
29520
- ledger_index: "validated",
29521
- peer: issuer,
29522
- },
29523
- ]);
29524
- }
29525
- async getTrustLine(address, issuer, currency) {
29526
- const response = await this.getTrustLines(address, issuer);
29527
- const trustLine = response.lines.find((line) => line.currency === currency);
29528
- return trustLine ?? null;
29529
- }
29530
- async accountActivatedInfo(address) {
29531
- const serverState = await this.getServerState();
29532
- const reserveBaseBn = BigInt(serverState.state.validated_ledger.reserve_base);
29533
- try {
29534
- const accountInfo = await this.getAccountInfo(address);
29535
- const balanceBn = BigInt(accountInfo.account_data.Balance);
29536
- return {
29537
- isActivated: balanceBn >= reserveBaseBn,
29538
- reserveBaseBn,
29539
- };
29540
- }
29541
- catch (error) {
29542
- if (error.message?.includes("actNotFound")) {
29543
- return { isActivated: false, reserveBaseBn };
29544
- }
29545
- throw error;
29546
- }
29547
- }
29548
- /**
29549
- * Waits for a transaction to be validated and returns its final status.
29550
- * Resolves to 'success' or throws an error with the failed status.
29551
- */
29552
- async waitForTransaction(txHash, { interval = 2_000, timeout = 20_000 } = {}) {
29553
- const startTime = Date.now();
29554
- while (true) {
29555
- try {
29556
- const response = await this.call("tx", [
29557
- {
29558
- transaction: txHash,
29559
- binary: false,
29560
- },
29561
- ]);
29562
- if (!response.validated) {
29563
- if (Date.now() - startTime > timeout) {
29564
- throw new Error(`Transaction ${txHash} not validated 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
- const status = response.meta?.TransactionResult;
29571
- if (status === XrplTxStatus.SUCCESS) {
29572
- return status;
29573
- }
29574
- else {
29575
- throw new Error(`Transaction failed with status: ${status}`);
29576
- }
29577
- }
29578
- catch (error) {
29579
- // txnNotFound = still pending or non-existent
29580
- if (error?.message?.includes("txnNotFound")) {
29581
- if (Date.now() - startTime > timeout) {
29582
- throw new Error(`Transaction ${txHash} not found within timeout`);
29583
- }
29584
- // eslint-disable-next-line @typescript-eslint/no-loop-func
29585
- await new Promise((res) => setTimeout(res, interval));
29586
- continue;
29587
- }
29588
- throw error;
29589
- }
29590
- }
29591
- }
29592
- async getServerState() {
29593
- return this.call("server_state", [{}]);
29594
- }
29595
- async getAccountInfo(address) {
29596
- return this.call("account_info", [
29597
- {
29598
- account: address,
29599
- ledger_index: "validated",
29600
- },
29601
- ]);
29602
- }
29603
- /**
29604
- * Returns the balance of the user in the native XRP token
29605
- * formatted as a string
29606
- */
29607
- async getNativeBalance(address) {
29608
- const [accountInfo, serverState] = await Promise.all([
29609
- this.getAccountInfo(address),
29610
- this.getServerState(),
29611
- ]);
29612
- const balance = BigInt(accountInfo.account_data.Balance);
29613
- const ownerCount = BigInt(accountInfo.account_data.OwnerCount);
29614
- const reserveBase = BigInt(serverState.state.validated_ledger.reserve_base);
29615
- const reserveIncrement = BigInt(serverState.state.validated_ledger.reserve_inc);
29616
- const reserveBalance = reserveBase + ownerCount * reserveIncrement;
29617
- const spendableBalance = balance - reserveBalance;
29618
- return formatBNToReadable(spendableBalance, 6);
29619
- }
29620
- /**
29621
- * Returns the balance of the user in the given issued currency (e.g. RLUSD)
29622
- * formatted as a string
29623
- */
29624
- async getIssuedCurrencyBalance(address, tokenAddress) {
29625
- const response = await this.getTrustLines(address);
29626
- const tokenBalance = response.lines.find((line) => `${line.currency}.${line.account}` === tokenAddress);
29627
- return tokenBalance?.balance || "0";
29628
- }
29629
- async call(method, params) {
29630
- const response = await fetch(this.rpcUrl, {
29631
- method: "POST",
29632
- headers: {
29633
- "Content-Type": "application/json",
29634
- },
29635
- body: JSON.stringify({
29636
- jsonrpc: "2.0",
29637
- id: 1,
29638
- method,
29639
- params,
29640
- }),
29641
- });
29642
- const data = await response.json();
29643
- if (!data.result) {
29644
- throw new Error(`Invalid response from RPC (${method})`);
29645
- }
29646
- if ("error" in data.result) {
29647
- throw new Error(`Error from RPC (${method}): ${data.result.error}`);
29648
- }
29649
- return data.result;
29650
- }
29651
- }
29652
-
29653
- const clientCache = new Map();
29654
- async function getClient(chain) {
29655
- const key = `${chain.chainType}:${chain.chainId}`;
29656
- if (clientCache.has(key)) {
29657
- return clientCache.get(key);
29658
- }
29659
- const client = await createClient(chain);
29660
- clientCache.set(key, client);
29661
- return client;
29662
- }
29663
- async function createClient(chain) {
29664
- switch (chain.chainType) {
29665
- case ChainType.EVM:
29666
- return new JsonRpcProvider(chain.rpc);
29667
- case ChainType.COSMOS:
29668
- const rpcUrl = await getWorkingCosmosRpcUrl(chain);
29669
- return (await StargateClient.connect(rpcUrl));
29670
- case ChainType.SOLANA:
29671
- return new Connection(SOLANA_RPC_URL);
29672
- case ChainType.BTC:
29673
- return null;
29674
- case ChainType.SUI:
29675
- return new SuiClient({
29676
- url: chain.rpc,
29677
- });
29678
- case ChainType.XRPL:
29679
- return new XrplRpcClient(chain.rpc);
29680
- case ChainType.STELLAR:
29681
- return new StellarRpcClient(chain.rpc);
29682
- }
29683
- }
29684
-
29685
- class StellarApiClient {
29686
- apiUrl;
29687
- constructor(apiUrl) {
29688
- this.apiUrl = apiUrl;
29689
- }
29690
- async getBaseReserve() {
29691
- const response = await fetch(`${this.apiUrl}/ledgers?order=desc&limit=1`);
29692
- if (!response.ok) {
29693
- throw new Error(`Failed to fetch ledgers: ${response.status}`);
29694
- }
29695
- const ledgers = await response.json();
29696
- const latestLedger = ledgers?._embedded.records?.[0];
29697
- if (latestLedger?.base_reserve_in_stroops == null) {
29698
- throw new Error("Invalid ledger data");
29699
- }
29700
- const baseReserveBn = BigInt(latestLedger.base_reserve_in_stroops);
29701
- return baseReserveBn;
29702
- }
29703
- }
29704
-
29705
- const DEFAULT_REFETCH_INTERVAL$1 = 20_000;
29706
- function useStellarAccountActivation({ address, chain, token, }) {
29707
- /**
29708
- * Checks if the destination account exists on the Stellar network
29709
- * Stellar accounts need to have a minimum balance before they can receive payments
29710
- */
29711
- const accountActivatedInfo = useQuery({
29712
- queryKey: keys().stellarAccountActivatedInfo(address, chain?.chainId, chain?.chainType),
29713
- queryFn: async () => {
29714
- if (chain?.chainType !== ChainType.STELLAR ||
29715
- token?.type !== ChainType.STELLAR) {
29716
- return null;
29717
- }
29718
- if (!address) {
29719
- throw new Error("Destination address is required");
29720
- }
29721
- // TODO: update types
29722
- const [horizonApiUrl] = chain?.horizonRpcList;
29723
- if (typeof horizonApiUrl !== "string") {
29724
- throw new Error("Invalid Horizon API URL");
29725
- }
29726
- const stellarApiClient = new StellarApiClient(horizonApiUrl);
29727
- const reserveBase = await stellarApiClient.getBaseReserve();
29728
- // Stellar accounts require two base reserves to be activated
29729
- // https://developers.stellar.org/docs/learn/fundamentals/lumens#minimum-balance
29730
- const accountReserveBase = reserveBase * BigInt(2);
29731
- const stellarRpcClient = await getClient(chain);
29732
- const isActivated = await stellarRpcClient.isAccountActivated(address);
29733
- return {
29734
- isActivated,
29735
- reserveBaseBn: accountReserveBase,
29736
- };
29737
- },
29738
- enabled: !!address && chain?.chainType === ChainType.STELLAR,
29739
- refetchInterval: DEFAULT_REFETCH_INTERVAL$1,
29740
- refetchOnWindowFocus: true,
29741
- });
29742
- return {
29743
- accountActivatedInfo,
29744
- };
29745
- }
29746
-
29747
29102
  const DEFAULT_REFRESH_INTERVAL_MS = 15000;
29748
29103
  const useEvmBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29749
29104
  const { isChainTypeConnected } = useWallet();
@@ -29938,6 +29293,8 @@ function useNativeTokenForChain(chain) {
29938
29293
  }
29939
29294
  };
29940
29295
  const nativeTokenForChainType = useMemo(() => {
29296
+ if (!chain)
29297
+ return undefined;
29941
29298
  return findNativeToken(getTokensForChainType(), chain);
29942
29299
  }, [chain]);
29943
29300
  return { nativeToken: nativeTokenForChainType };
@@ -30095,136 +29452,772 @@ const useStellarNativeBalance = ({ address, chain, }) => {
30095
29452
  userAddress: address,
30096
29453
  enabled: chain?.chainType === ChainType.STELLAR,
30097
29454
  });
30098
- const balance = useMemo(() => {
30099
- if (nativeToken?.decimals && rawBalance) {
30100
- return {
30101
- decimals: nativeToken.decimals,
30102
- value: parseToBigInt(rawBalance, nativeToken.decimals),
30103
- };
30104
- }
30105
- }, [nativeToken?.decimals, rawBalance]);
30106
- return {
30107
- balance,
30108
- isLoading,
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,
30109
29916
  };
30110
- };
30111
- const useNativeBalance = (chain) => {
30112
- const { connectedAddresses } = useWallet();
30113
- const { data: cosmosAddressForChain } = useCosmosForChain(chain);
30114
- // Cosmos is a special case because the address changes on every chain
30115
- // so we can't use the default cosmos connected address
30116
- const { balance: nativeCosmosBalance, isLoading: isCosmosLoading } = useCosmosNativeBalance({
30117
- address: cosmosAddressForChain,
30118
- chain,
30119
- });
30120
- const { balance: nativeEvmBalance, isLoading: isEvmLoading } = useEvmNativeBalance({ address: connectedAddresses[ChainType.EVM], chain });
30121
- const { balance: nativeBitcoinBalance, isLoading: isBitcoinLoading } = useBitcoinNativeBalance({
30122
- address: connectedAddresses[ChainType.BTC],
30123
- chain,
30124
- });
30125
- const { balance: nativeSolanaBalance, isLoading: isSolanaLoading } = useSolanaNativeBalance({
30126
- address: connectedAddresses[ChainType.SOLANA],
30127
- chain,
30128
- });
30129
- const { balance: nativeSuiBalance, isLoading: isSuiLoading } = useSuiNativeBalance({
30130
- address: connectedAddresses[ChainType.SUI],
30131
- chain,
30132
- });
30133
- const { balance: nativeXrplBalance, isLoading: isXrpLoading } = useXrplNativeBalance({
30134
- address: connectedAddresses[ChainType.XRPL],
30135
- chain,
30136
- });
30137
- const { balance: nativeStellarBalance, isLoading: isStellarLoading } = useStellarNativeBalance({
30138
- address: connectedAddresses[ChainType.STELLAR],
30139
- chain,
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
+ ],
30140
29949
  });
30141
- const { nativeBalance, nativeBalanceFormatted } = useMemo(() => {
30142
- let balance;
30143
- switch (chain?.chainType) {
30144
- case ChainType.EVM:
30145
- balance = nativeEvmBalance;
30146
- break;
30147
- case ChainType.COSMOS:
30148
- balance = nativeCosmosBalance;
30149
- break;
30150
- case ChainType.BTC:
30151
- balance = nativeBitcoinBalance;
30152
- break;
30153
- case ChainType.SOLANA:
30154
- balance = nativeSolanaBalance;
30155
- break;
30156
- case ChainType.SUI:
30157
- balance = nativeSuiBalance;
30158
- break;
30159
- case ChainType.XRPL:
30160
- balance = nativeXrplBalance;
30161
- break;
30162
- case ChainType.STELLAR:
30163
- balance = nativeStellarBalance;
30164
- }
30165
- const balanceFormatted = !!balance
30166
- ? formatBNToReadable(balance.value, balance.decimals)
30167
- : undefined;
30168
- return {
30169
- nativeBalance: balance,
30170
- nativeBalanceFormatted: balanceFormatted,
30171
- };
30172
- }, [
30173
- chain?.chainType,
30174
- nativeEvmBalance,
30175
- nativeCosmosBalance,
30176
- nativeBitcoinBalance,
30177
- nativeSolanaBalance,
30178
- nativeSuiBalance,
30179
- nativeXrplBalance,
30180
- nativeStellarBalance,
30181
- ]);
30182
- const isLoading = useMemo(() => {
29950
+ };
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,
29962
+ };
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(() => {
30183
29993
  if (!chain?.chainType)
30184
29994
  return false;
30185
29995
  switch (chain.chainType) {
30186
29996
  case ChainType.EVM:
30187
- return isEvmLoading;
29997
+ return isEvmSignerReady;
30188
29998
  case ChainType.COSMOS:
30189
- return isCosmosLoading;
29999
+ return isCosmosSignerReady;
30190
30000
  case ChainType.BTC:
30191
- return isBitcoinLoading;
30001
+ return isBitcoinSignerReady;
30192
30002
  case ChainType.SOLANA:
30193
- return isSolanaLoading;
30003
+ return isSolanaSignerReady;
30194
30004
  case ChainType.SUI:
30195
- return isSuiLoading;
30005
+ return isSuiSignerReady;
30196
30006
  case ChainType.XRPL:
30197
- return isXrpLoading;
30007
+ return isXrplSignerReady;
30198
30008
  case ChainType.STELLAR:
30199
- return isStellarLoading;
30009
+ return isStellarSignerReady;
30200
30010
  }
30201
30011
  }, [
30202
30012
  chain?.chainType,
30203
- isEvmLoading,
30204
- isCosmosLoading,
30205
- isBitcoinLoading,
30206
- isSolanaLoading,
30207
- isSuiLoading,
30208
- isXrpLoading,
30209
- isStellarLoading,
30013
+ isEvmSignerReady,
30014
+ isCosmosSignerReady,
30015
+ isBitcoinSignerReady,
30016
+ isSolanaSignerReady,
30017
+ isSuiSignerReady,
30018
+ isXrplSignerReady,
30019
+ isStellarSignerReady,
30210
30020
  ]);
30211
- return { nativeBalance, nativeBalanceFormatted, isLoading };
30021
+ return {
30022
+ isSignerReady,
30023
+ evmSigner,
30024
+ cosmosSigner,
30025
+ bitcoinSigner,
30026
+ solanaSigner,
30027
+ suiSigner,
30028
+ xrplSigner,
30029
+ stellarSigner,
30030
+ };
30212
30031
  };
30213
30032
 
30214
- function useHederaAccountActivation({ address, chain, token }) {
30215
- const { balance: destNativeEvmBalance } = useEvmNativeBalance({
30216
- chain,
30217
- address,
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,
30218
30119
  });
30219
- const isHederaAccountActivated = useMemo(() => {
30220
- if (token?.chainId !== CHAIN_IDS.HEDERA)
30221
- return true;
30222
- if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase())
30223
- return true;
30224
- return (!!destNativeEvmBalance?.value && destNativeEvmBalance.value > BigInt(0));
30225
- }, [token?.chainId, token?.address, destNativeEvmBalance?.value]);
30226
30120
  return {
30227
- isHederaAccountActivated,
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
+ };
30160
+ };
30161
+
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,
30218
+ });
30219
+ return {
30220
+ accountActivatedInfo,
30228
30221
  };
30229
30222
  }
30230
30223
 
@@ -30752,6 +30745,161 @@ const useSingleTokenPrice = (tokenData) => {
30752
30745
  return { tokenPrice, getUSDValue };
30753
30746
  };
30754
30747
 
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
+
30755
30903
  const MAX_COINGECKO_QUERY_TOKENS = 100;
30756
30904
  const fetchHistoricalData = async (coingeckoId, timeFrame) => {
30757
30905
  const now = Math.floor(Date.now() / 1000);
@@ -30902,24 +31050,20 @@ const calculateTotalNativeFees = ({ expressFeeCost, firstFeeCost, firstGasCost,
30902
31050
  (sameTokenBetweenFees
30903
31051
  ? BigInt(firstFeeCost?.amount ?? "0") + BigInt(firstGasCost?.amount ?? "0")
30904
31052
  : BigInt(firstGasCost?.amount ?? "0"));
30905
- const isFromBalanceEnoughToSwap = ({ isFromTokenNative, fromAmount, totalFeesInNativeTokenPlusRatio, nativeTokenBalanceFromChainWei, }) => {
30906
- const fromAmountBigInt = BigInt(fromAmount ?? "0");
30907
- const totalFeesInNativeTokenPlusRatioBigInt = totalFeesInNativeTokenPlusRatio;
30908
- const nativeTokenBalanceFromChainWeiBigInt = nativeTokenBalanceFromChainWei;
30909
- return isFromTokenNative
30910
- ? fromAmountBigInt + totalFeesInNativeTokenPlusRatioBigInt <=
30911
- nativeTokenBalanceFromChainWeiBigInt
30912
- : totalFeesInNativeTokenPlusRatioBigInt <=
30913
- nativeTokenBalanceFromChainWeiBigInt;
30914
- };
30915
- const calculateMinAmountValueWarnMsg = ({ isFromTokenNative, nativeTokenBalanceFromChainWei, sourceChainNativeTokenDecimals, totalFeesInNativeTokenPlusRatio, }) => isFromTokenNative
30916
- ? (() => {
30917
- const minAmount = nativeTokenBalanceFromChainWei - totalFeesInNativeTokenPlusRatio;
30918
- return minAmount > BigInt(0)
30919
- ? formatBNToReadable(minAmount, sourceChainNativeTokenDecimals)
30920
- : "0";
30921
- })()
30922
- : undefined;
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
+ };
30923
31067
  /**
30924
31068
  * Calculates the estimated duration of a route
30925
31069
  *
@@ -30958,12 +31102,10 @@ const formatEstimatedRouteDuration = ({ estimatedRouteDuration, isSingleChainRou
30958
31102
  * @returns {Object} An object containing various estimate results and calculations, including token information,
30959
31103
  * amounts, fees, gas costs, and other relevant data for the transaction.
30960
31104
  */
30961
- const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, collectFees, nativeTokenBalanceFromChainWei, }) => {
31105
+ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, collectFees, nativeTokenBalanceFromChainWei, tempoFeeData, }) => {
30962
31106
  const fromToken = findToken(tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken);
30963
31107
  const fromAmount = squidRoute?.estimate?.fromAmount;
30964
31108
  const fromAmountFormatted = formatAmount(fromAmount, fromToken?.decimals);
30965
- const sourceChainNativeToken = findNativeToken(tokens, fromChain);
30966
- const destChainNativeToken = findNativeToken(tokens, toChain);
30967
31109
  const toAmountUSD = squidRoute?.estimate?.toAmountUSD;
30968
31110
  const exchangeRate = squidRoute?.estimate.exchangeRate ?? "0";
30969
31111
  const toAmountMinUSD = squidRoute?.estimate.toAmountMinUSD ?? "0";
@@ -30982,10 +31124,6 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
30982
31124
  const expectedGasRefundCostUSD = convertTokenAmountToUSD(formatBNToReadable(expectedGasRefundCost, firstFeeCost?.token.decimals ?? 18), firstFeeCost?.token.usdPrice ?? "0");
30983
31125
  const sameTokenBetweenFees = firstFeeCost?.token.address === firstGasCost?.token.address &&
30984
31126
  firstFeeCost?.token.chainId === firstGasCost?.token.chainId;
30985
- const isFromTokenNative =
30986
- // TODO: temporary fix, currently nativeCurrency.symbol is not always in uppercase
30987
- fromToken?.symbol.toUpperCase() ===
30988
- fromChain?.nativeCurrency.symbol.toUpperCase();
30989
31127
  const totalNativeFees = calculateTotalNativeFees({
30990
31128
  expressFeeCost,
30991
31129
  firstFeeCost,
@@ -30993,19 +31131,32 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
30993
31131
  sameTokenBetweenFees,
30994
31132
  });
30995
31133
  const totalFeesInNativeTokenPlusRatio = (totalNativeFees * BigInt(110)) / BigInt(100);
30996
- const fromBalanceEnoughToSwap = isFromBalanceEnoughToSwap({
30997
- isFromTokenNative,
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,
30998
31147
  fromAmount,
30999
- fromTokenDecimals: fromToken?.decimals,
31000
- totalFeesInNativeTokenPlusRatio,
31001
- nativeTokenBalanceFromChainWei,
31148
+ networkFeesWei,
31002
31149
  });
31003
- const minAmountValueWarnMsg = calculateMinAmountValueWarnMsg({
31004
- isFromTokenNative,
31005
- nativeTokenBalanceFromChainWei,
31006
- sourceChainNativeTokenDecimals: sourceChainNativeToken?.decimals,
31007
- totalFeesInNativeTokenPlusRatio,
31150
+ const minAmount = calculateMinAmountValueWarnMsg({
31151
+ chainFeeParams,
31152
+ // gasTokenDecimals: chainFeeParams,
31153
+ networkFeesWei,
31008
31154
  });
31155
+ const minAmountValueWarnMsg = minAmount
31156
+ ? formatBNToReadable(minAmount, chainFeeParams?.fromTokenPaysNetworkFee
31157
+ ? fromToken?.decimals
31158
+ : undefined)
31159
+ : undefined;
31009
31160
  const isSingleChainRoute = fromChain?.chainId === toChain?.chainId;
31010
31161
  const estimatedRouteDuration = formatEstimatedRouteDuration({
31011
31162
  estimatedRouteDuration: squidRoute?.estimate?.estimatedRouteDuration,
@@ -31015,8 +31166,6 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31015
31166
  fromToken,
31016
31167
  fromAmount,
31017
31168
  fromAmountFormatted,
31018
- sourceChainNativeToken,
31019
- destChainNativeToken,
31020
31169
  toAmountUSD,
31021
31170
  exchangeRate,
31022
31171
  toAmountMinUSD,
@@ -31031,10 +31180,10 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31031
31180
  expectedGasRefundCost,
31032
31181
  expectedGasRefundCostUSD,
31033
31182
  sameTokenBetweenFees,
31034
- isFromTokenNative,
31183
+ fromTokenPaysNetworkFee: chainFeeParams?.fromTokenPaysNetworkFee ?? false,
31035
31184
  totalNativeFees,
31036
31185
  totalFeesInNativeTokenPlusRatio,
31037
- fromBalanceEnoughToSwap,
31186
+ gasBalanceEnough,
31038
31187
  minAmountValueWarnMsg,
31039
31188
  estimatedRouteDuration,
31040
31189
  };
@@ -31070,28 +31219,6 @@ const calculateTotalWithRefundEstimate = (allFeeCosts, expectedGasRefundCost, ge
31070
31219
  feeToken: firstFeeCost?.token,
31071
31220
  };
31072
31221
  };
31073
- /**
31074
- * Calculates the proposed gas amount for the destination chain.
31075
- *
31076
- * @param destChainNativeToken - The symbol of the native token for the destination chain.
31077
- * @returns An object containing the proposed gas amount value and the currency symbol.
31078
- */
31079
- const getProposedGasDestinationAmount = (destChainNativeToken) => {
31080
- const gasAmounts = {
31081
- GLMR: 5.289,
31082
- ETH: 0.0009,
31083
- AVAX: 0.115,
31084
- BNB: 0.00425,
31085
- FTM: 4.45,
31086
- CELO: 3.052,
31087
- KAVA: 2.339,
31088
- MATIC: 1.795,
31089
- };
31090
- return {
31091
- value: gasAmounts[destChainNativeToken ?? ""] ?? 0,
31092
- currency: destChainNativeToken,
31093
- };
31094
- };
31095
31222
 
31096
31223
  function useSendTransactionGas({ chain, token, from, }) {
31097
31224
  return useQuery({
@@ -31113,7 +31240,11 @@ function useSendTransactionGas({ chain, token, from, }) {
31113
31240
  // Some RPC providers require the sender to have enough balance, otherwise estimation reverts
31114
31241
  // so we'll try to use the user provided address when possible
31115
31242
  const sender = from || dummyAddress;
31116
- if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase()) {
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) {
31117
31248
  const gas = await client.estimateGas({
31118
31249
  from: sender,
31119
31250
  to: dummyAddress,
@@ -31133,7 +31264,14 @@ function useSendTransactionGas({ chain, token, from, }) {
31133
31264
  data,
31134
31265
  chainId: chain.chainId,
31135
31266
  });
31136
- return gas * maxFeePerGas;
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;
31137
31275
  }
31138
31276
  case ChainType.COSMOS: {
31139
31277
  // TODO: get gas estimation from backend
@@ -31181,18 +31319,24 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31181
31319
  from,
31182
31320
  });
31183
31321
  const { nativeBalance } = useNativeBalance(chain);
31184
- const isNativeBalanceEnoughToPayGasFees = useMemo(() => {
31185
- if (!nativeBalance?.value || !amount || !token?.decimals) {
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)
31186
31333
  return false;
31187
- }
31188
- const isTokenNative = token.address.toLowerCase() ===
31189
- chainTypeToNativeTokenAddressMap[token.type].toLowerCase();
31190
- if (isTokenNative) {
31191
- return (parseToBigInt(amount, token.decimals) + estimatedGas <=
31192
- nativeBalance.value);
31193
- }
31194
- return estimatedGas <= nativeBalance.value;
31195
- }, [amount, estimatedGas, nativeBalance?.value, token]);
31334
+ return isGasBalanceEnough({
31335
+ fromAmount: parseToBigInt(amount, token.decimals).toString(),
31336
+ networkFeesWei: estimatedGas,
31337
+ chainFeeParams,
31338
+ });
31339
+ }, [amount, estimatedGas, token, chainFeeParams]);
31196
31340
  const isBalanceEnough = useMemo(() => {
31197
31341
  if (token?.decimals == null || !balance || !amount)
31198
31342
  return false;
@@ -31200,28 +31344,30 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31200
31344
  parseToBigInt(amount, token.decimals));
31201
31345
  }, [amount, balance, token?.decimals]);
31202
31346
  const minAmountValueWarnMsg = useMemo(() => {
31203
- if (!token?.address || !nativeBalance?.value || !estimatedGas)
31347
+ if (!token?.address || !estimatedGas)
31348
+ return undefined;
31349
+ if (!chainFeeParams)
31204
31350
  return undefined;
31205
- const isFromTokenNative = token.address.toLowerCase() ===
31206
- chainTypeToNativeTokenAddressMap[token.type].toLowerCase();
31207
- return calculateMinAmountValueWarnMsg({
31208
- isFromTokenNative,
31209
- nativeTokenBalanceFromChainWei: nativeBalance.value,
31210
- sourceChainNativeTokenDecimals: nativeBalance.decimals,
31211
- totalFeesInNativeTokenPlusRatio: estimatedGas,
31351
+ const minAmount = calculateMinAmountValueWarnMsg({
31352
+ chainFeeParams,
31353
+ // gasTokenDecimals: chainFeeParams.fromTokenPaysNetworkFee
31354
+ // ? token.decimals
31355
+ // : undefined,
31356
+ networkFeesWei: estimatedGas,
31212
31357
  });
31213
- }, [
31214
- estimatedGas,
31215
- nativeBalance?.decimals,
31216
- nativeBalance?.value,
31217
- token?.address,
31218
- token?.type,
31219
- ]);
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]);
31220
31365
  return {
31221
31366
  estimatedGas,
31222
31367
  isBalanceEnough,
31368
+ tokenPaysNetworkFee: chainFeeParams?.fromTokenPaysNetworkFee ?? false,
31223
31369
  isLoading,
31224
- isNativeBalanceEnoughToPayGasFees,
31370
+ isGasBalanceEnough: gasBalanceEnough,
31225
31371
  minAmountValueWarnMsg,
31226
31372
  };
31227
31373
  }
@@ -32107,7 +32253,7 @@ const useApproval = ({ squidRoute, }) => {
32107
32253
  const publicClient = usePublicClient();
32108
32254
  const queryClient = useQueryClient();
32109
32255
  const squid = useSquidStore((state) => state.squid);
32110
- const { fromChain, fromToken, fromAmount, toAmount, isSameChain } = useSwap();
32256
+ const { fromChain, fromToken, fromPrice, isSameChain } = useSwap();
32111
32257
  const { evmSigner } = useSigner({ chain: fromChain });
32112
32258
  const { connector: activeConnector } = useAccount();
32113
32259
  const { getChainType } = useSquidChains();
@@ -32280,7 +32426,7 @@ const useApproval = ({ squidRoute, }) => {
32280
32426
  // This is to ensure we're using the latest expiry timestamp
32281
32427
  if (squidRoute) {
32282
32428
  queryClient.refetchQueries({
32283
- queryKey: keys().transaction(squidRoute.params.fromChain, squidRoute.params.toChain, squidRoute.params.toToken, squidRoute.params.fromToken, fromAmount, toAmount, 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,
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,
32284
32430
  // TODO: update types
32285
32431
  squidRoute.params?.overrideGasRefundAddress),
32286
32432
  });
@@ -32299,8 +32445,10 @@ const AXELAR_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/ass
32299
32445
  const useEstimate = (squidRoute) => {
32300
32446
  const collectFees = useConfigStore((state) => state.config.collectFees);
32301
32447
  const { tokens } = useSquidTokens();
32302
- const { fromChain, toChain } = useSwap();
32448
+ const { fromChain, toChain, fromPrice } = useSwap();
32303
32449
  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 });
32304
32452
  const estimateResults = useMemo(() => calculateEstimateResults({
32305
32453
  squidRoute,
32306
32454
  tokens,
@@ -32308,8 +32456,17 @@ const useEstimate = (squidRoute) => {
32308
32456
  toChain,
32309
32457
  collectFees: !!collectFees && collectFees.fee > 0,
32310
32458
  nativeTokenBalanceFromChainWei: nativeBalance?.value ?? BigInt("0"),
32311
- }), [squidRoute, tokens, fromChain, toChain, collectFees, nativeBalance]);
32312
- const balanceFormatted = useMultiChainBalance({
32459
+ tempoFeeData: tempoFeeData ?? undefined,
32460
+ }), [
32461
+ squidRoute,
32462
+ tokens,
32463
+ fromChain,
32464
+ toChain,
32465
+ collectFees,
32466
+ nativeBalance,
32467
+ tempoFeeData,
32468
+ ]);
32469
+ const fromBalanceFormatted = useMultiChainBalance({
32313
32470
  chain: fromChain,
32314
32471
  token: estimateResults.fromToken,
32315
32472
  userAddress: squidRoute?.params.fromAddress ?? "",
@@ -32321,7 +32478,6 @@ const useEstimate = (squidRoute) => {
32321
32478
  estimateResults.expectedGasRefundCost,
32322
32479
  getUSDValue,
32323
32480
  ]);
32324
- const proposedGasDestinationAmount = useMemo(() => getProposedGasDestinationAmount(estimateResults.destChainNativeToken?.symbol), [estimateResults.destChainNativeToken]);
32325
32481
  const { feeCostsFormatted, totalFeeCostsUsd } = useMemo(() => {
32326
32482
  const feeCosts = squidRoute?.estimate.feeCosts ?? [];
32327
32483
  const feeCostsRenamed = [];
@@ -32380,19 +32536,18 @@ const useEstimate = (squidRoute) => {
32380
32536
  totalFeeCostsUsd: totalFeeCostsUsdFormatted,
32381
32537
  };
32382
32538
  }, [squidRoute?.estimate.feeCosts]);
32383
- const slippageFormatted =
32384
- // TODO: update types
32385
- Number(squidRoute?.estimate?.aggregateSlippage ?? 0).toFixed(2) +
32386
- "%";
32387
- const enoughBalanceToSwap = +balanceFormatted >= 0 &&
32388
- +balanceFormatted > +estimateResults.fromAmountFormatted;
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]);
32389
32545
  return {
32390
32546
  ...estimateResults,
32391
- balanceFormatted,
32547
+ fromBalanceFormatted,
32392
32548
  slippageFormatted,
32393
32549
  totalWithRefundEstimate,
32394
- proposedGasDestinationAmount,
32395
- enoughBalanceToSwap,
32550
+ fromBalanceEnoughToSwap,
32396
32551
  feeCostsFormatted,
32397
32552
  totalFeeCostsUsd,
32398
32553
  };
@@ -36093,12 +36248,8 @@ const useGetRoute = () => {
36093
36248
  * These data will be used to trigger the transaction
36094
36249
  * @returns {Route} Route data
36095
36250
  */
36096
- return useMutation(async ({ fromChain, toChain, fromToken, toToken, sourceUserAddress, destinationAddress, fromPrice = "", toPrice = "", bypassGuardrails, quoteOnly, fromChainType, postHook, preHook, overrideGasRefundAddress, }) => {
36097
- if (!fromChain ||
36098
- !toChain ||
36099
- !fromToken ||
36100
- !toToken ||
36101
- (!fromPrice && !toPrice)) {
36251
+ return useMutation(async ({ fromChain, toChain, fromToken, toToken, sourceUserAddress, destinationAddress, fromPrice, bypassGuardrails, quoteOnly, fromChainType, postHook, preHook, overrideGasRefundAddress, }) => {
36252
+ if (!fromChain || !toChain || !fromToken || !toToken || !fromPrice) {
36102
36253
  return undefined;
36103
36254
  }
36104
36255
  // Dispatch requestQuote event
@@ -36108,7 +36259,6 @@ const useGetRoute = () => {
36108
36259
  fromToken: fromToken.address,
36109
36260
  toToken: toToken.address,
36110
36261
  fromAmount: fromPrice,
36111
- toAmount: toPrice,
36112
36262
  fromAddress: sourceUserAddress,
36113
36263
  toAddress: destinationAddress,
36114
36264
  });
@@ -36117,7 +36267,6 @@ const useGetRoute = () => {
36117
36267
  const fromTokenAddress = fromToken.address;
36118
36268
  const toTokenAddress = toToken.address;
36119
36269
  const fromAmount = parseToBigInt(fromPrice?.toString() ?? "0", fromToken?.decimals).toString();
36120
- const toAmount = parseToBigInt(toPrice?.toString() ?? "0", toToken?.decimals).toString();
36121
36270
  const fromAddress = sourceUserAddress ??
36122
36271
  chainTypeToZeroAddressMap[fromChainType ?? ChainType.EVM];
36123
36272
  const params = {
@@ -36125,7 +36274,6 @@ const useGetRoute = () => {
36125
36274
  fromToken: fromTokenAddress,
36126
36275
  fromAddress,
36127
36276
  fromAmount,
36128
- toAmount,
36129
36277
  toChain,
36130
36278
  toToken: toTokenAddress,
36131
36279
  toAddress: destinationAddress ?? "",
@@ -36147,7 +36295,7 @@ const useGetRoute = () => {
36147
36295
  });
36148
36296
  // Cache the route data
36149
36297
  // Useful when the getRoute mutation is called from another hook
36150
- queryClient.setQueryData(keys().transaction(fromChain, toChain, toToken.address, fromToken.address, fromPrice, toPrice, config.slippage, config.enableGetGasOnDestination, sourceUserAddress, config.degenMode, destinationAddress, swapRoute?.fallbackAddress, quoteOnly, fromChainType, config.preHook, config.postHook, overrideGasRefundAddress), route);
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);
36151
36299
  return route;
36152
36300
  });
36153
36301
  };
@@ -36161,7 +36309,7 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36161
36309
  const depositRefundAddress = useSwapRoutePersistStore((store) => store.swapRoute?.depositRefundAddress);
36162
36310
  const { isAvailableAsPaymentMethod, isEnabled: isDepositAddressEnabled } = useDepositAddress();
36163
36311
  const getRouteMutation = useGetRoute();
36164
- const { fromChain, toChain, fromAmount, toAmount, destinationAddress: { address: destinationAddress } = {}, fromToken, toToken, } = useSwap();
36312
+ const { fromChain, toChain, fromPrice, destinationAddress: { address: destinationAddress } = {}, fromToken, toToken, } = useSwap();
36165
36313
  const { connectedAddress: { address: sourceConnectedAddress }, } = useMultiChainWallet(fromChain);
36166
36314
  // When the payment method is deposit address, users can specify a refund address on the source chain
36167
36315
  // Tokens will be sent to this address in case of swap failure
@@ -36170,15 +36318,13 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36170
36318
  const sourceUserAddress = isDepositAddressEnabled && isAvailableAsPaymentMethod
36171
36319
  ? depositRefundAddress ?? sourceConnectedAddress
36172
36320
  : sourceConnectedAddress;
36173
- const squidRouteQueryKeys = useMemo(() => keys().transaction(fromChain?.chainId, toChain?.chainId, toToken?.address, fromToken?.address, fromAmount, toAmount, config.slippage, config.enableGetGasOnDestination, sourceUserAddress, config.degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChain?.chainType, config.preHook, config.postHook, config.overrideGasRefundAddress), [
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), [
36174
36322
  fromChain?.chainId,
36175
36323
  toChain?.chainId,
36176
36324
  toToken?.address,
36177
36325
  fromToken?.address,
36178
- fromAmount,
36179
- toAmount,
36326
+ fromPrice,
36180
36327
  config.slippage,
36181
- config.enableGetGasOnDestination,
36182
36328
  sourceUserAddress,
36183
36329
  config.degenMode,
36184
36330
  destinationAddress,
@@ -36192,8 +36338,8 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36192
36338
  const queryEnabled = enabled != undefined
36193
36339
  ? enabled
36194
36340
  : squid !== undefined &&
36195
- ((fromAmount !== undefined && fromAmount !== "0") ||
36196
- (toAmount !== undefined && toAmount !== "0")) &&
36341
+ fromPrice !== undefined &&
36342
+ fromPrice !== "0" &&
36197
36343
  toChain?.chainId !== undefined &&
36198
36344
  toToken?.address !== undefined;
36199
36345
  const queryClient = useQueryClient();
@@ -36211,8 +36357,7 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36211
36357
  toToken,
36212
36358
  sourceUserAddress,
36213
36359
  destinationAddress,
36214
- fromPrice: fromAmount,
36215
- toPrice: toAmount,
36360
+ fromPrice,
36216
36361
  bypassGuardrails: config.degenMode,
36217
36362
  quoteOnly,
36218
36363
  fromChainType: fromChain?.chainType,
@@ -36451,35 +36596,6 @@ const useAvatar = (seed = zeroAddress) => {
36451
36596
  return avatar || "";
36452
36597
  };
36453
36598
 
36454
- const useUserParams = () => {
36455
- const enableGetGasOnDestination = useConfigStore((state) => state.config.enableGetGasOnDestination);
36456
- const { fromToken, toToken, toChain, fromChain } = useSwap();
36457
- // =============
36458
- // GAS
36459
- // =============
36460
- const getGasOnDestSupportedForThisRoute = useMemo(() =>
36461
- // Not supporting get gas on dest for same chains
36462
- fromChain?.chainId !== toChain?.chainId &&
36463
- // If the destination chain is cosmos, we don't support getting gas there
36464
- toChain?.chainType !== ChainType.COSMOS &&
36465
- // Not supporting get gas on dest for same tokens (bridge)
36466
- ((fromToken?.subGraphIds?.some((sgi) => !!toToken?.subGraphIds?.includes(sgi)) &&
36467
- toToken?.subGraphIds?.some((sgi) => !!fromToken?.subGraphIds?.includes(sgi))) ||
36468
- // Except for uusdc -> uusdc
36469
- (fromToken?.subGraphIds?.includes("uusdc") &&
36470
- toToken?.subGraphIds?.includes("uusdc"))), [
36471
- fromChain?.chainId,
36472
- fromToken?.subGraphIds,
36473
- toChain?.chainId,
36474
- toToken?.subGraphIds,
36475
- toChain?.chainType,
36476
- ]);
36477
- return {
36478
- gasEnabled: enableGetGasOnDestination && getGasOnDestSupportedForThisRoute,
36479
- getGasOnDestSupportedForThisRoute,
36480
- };
36481
- };
36482
-
36483
36599
  const useAddToken = (chainToCompare, tokenToCompare) => {
36484
36600
  const { chain: currentEvmChain } = useAccount();
36485
36601
  const { connector } = useAccount();
@@ -36907,5 +37023,5 @@ const SquidProvider = ({ children, config, placeholder, }) => {
36907
37023
  React.createElement(CosmosProvider, null, children)))))))))) : (placeholder);
36908
37024
  };
36909
37025
 
36910
- 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, 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, useHederaTokenAssociations as z };
36911
- //# sourceMappingURL=index-DnkELFs9.js.map
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