@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.
- package/dist/core/constants.d.ts +3 -0
- package/dist/core/queries/queries-keys.d.ts +1 -1
- package/dist/core/types/config.d.ts +0 -1
- package/dist/core/types/route.d.ts +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/store/useSquidStore.d.ts +1 -2
- package/dist/hooks/swap/useSwap.d.ts +2 -4
- package/dist/hooks/tokens/useSourceChainGasToken.d.ts +11 -0
- package/dist/hooks/transaction/send/useEstimateSendTransactionGas.d.ts +6 -2
- package/dist/hooks/transaction/useEstimate.d.ts +5 -11
- package/dist/hooks/transaction/useGetRoute.d.ts +0 -1
- package/dist/hooks/transaction/useTempoFeeCheck.d.ts +11 -0
- package/dist/{index-DnkELFs9.js → index-B4aeecpP.js} +1319 -1203
- package/dist/index-B4aeecpP.js.map +1 -0
- package/dist/{index-Bg7CS2Uo.js → index-CaI-xWCW.js} +1316 -1200
- package/dist/index-CaI-xWCW.js.map +1 -0
- package/dist/{index.es-tWag56u3.js → index.es-BXf9jwuI.js} +3 -3
- package/dist/{index.es-tWag56u3.js.map → index.es-BXf9jwuI.js.map} +1 -1
- package/dist/{index.es-BQGUcysL.js → index.es-DAfqL2H0.js} +3 -3
- package/dist/{index.es-BQGUcysL.js.map → index.es-DAfqL2H0.js.map} +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.js +3 -3
- package/dist/{secretService-Bs5SPC6i.js → secretService-CIYxEkTN.js} +3 -3
- package/dist/{secretService-Bs5SPC6i.js.map → secretService-CIYxEkTN.js.map} +1 -1
- package/dist/{secretService-BXleHutG.js → secretService-Cld4gYfG.js} +3 -3
- package/dist/{secretService-BXleHutG.js.map → secretService-Cld4gYfG.js.map} +1 -1
- package/dist/services/internal/assetsService.d.ts +2 -2
- package/dist/services/internal/estimateService.d.ts +13 -27
- package/dist/services/internal/tempoService.d.ts +82 -0
- package/dist/{stellarService.client-li6iEHAu.js → stellarService.client-COeQeah_.js} +3 -3
- package/dist/{stellarService.client-li6iEHAu.js.map → stellarService.client-COeQeah_.js.map} +1 -1
- package/dist/{stellarService.client-TTYw1-aB.js → stellarService.client-ocLzRIB4.js} +3 -3
- package/dist/{stellarService.client-TTYw1-aB.js.map → stellarService.client-ocLzRIB4.js.map} +1 -1
- package/dist/tests/networkGasToken.test.d.ts +1 -0
- package/dist/tests/tempoService.test.d.ts +1 -0
- package/package.json +1 -1
- package/dist/hooks/user/useUserParams.d.ts +0 -4
- package/dist/index-Bg7CS2Uo.js.map +0 -1
- 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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
22950
|
-
t.chainId == chain
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
-
|
|
27584
|
-
|
|
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
|
-
|
|
27794
|
-
|
|
27795
|
-
|
|
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
|
-
|
|
27840
|
-
|
|
27841
|
-
|
|
27842
|
-
|
|
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
|
-
|
|
27845
|
-
|
|
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 (
|
|
27848
|
-
|
|
27820
|
+
if ("result" in simulateTxResponse && simulateTxResponse.result != null) {
|
|
27821
|
+
const native = scValToNative(simulateTxResponse.result.retval);
|
|
27822
|
+
return native.toString();
|
|
27849
27823
|
}
|
|
27850
|
-
|
|
27824
|
+
throw new Error("Failed to fetch balance");
|
|
27851
27825
|
}
|
|
27852
|
-
async
|
|
27853
|
-
const
|
|
27854
|
-
|
|
27855
|
-
|
|
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
|
-
|
|
27858
|
-
|
|
27859
|
-
|
|
27864
|
+
}
|
|
27865
|
+
async isAccountActivated(address) {
|
|
27866
|
+
try {
|
|
27867
|
+
await this.getAccount(address);
|
|
27868
|
+
return true;
|
|
27860
27869
|
}
|
|
27861
|
-
|
|
27862
|
-
|
|
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
|
|
27867
|
-
|
|
27868
|
-
|
|
27869
|
-
|
|
27870
|
-
|
|
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
|
|
27885
|
+
return transactionResponse;
|
|
27886
|
+
}
|
|
27887
|
+
async prepareTransaction(transaction) {
|
|
27888
|
+
return this.server.prepareTransaction(transaction);
|
|
27873
27889
|
}
|
|
27874
27890
|
}
|
|
27875
27891
|
|
|
27876
|
-
|
|
27877
|
-
|
|
27878
|
-
|
|
27879
|
-
|
|
27880
|
-
|
|
27881
|
-
|
|
27882
|
-
|
|
27883
|
-
|
|
27884
|
-
|
|
27885
|
-
|
|
27886
|
-
|
|
27887
|
-
|
|
27888
|
-
|
|
27889
|
-
|
|
27890
|
-
|
|
27891
|
-
|
|
27892
|
-
|
|
27893
|
-
|
|
27894
|
-
|
|
27895
|
-
|
|
27896
|
-
|
|
27897
|
-
|
|
27898
|
-
|
|
27899
|
-
|
|
27900
|
-
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
|
|
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
|
-
|
|
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
|
|
27913
|
-
|
|
27914
|
-
|
|
27915
|
-
|
|
27916
|
-
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
|
|
27921
|
-
|
|
27922
|
-
|
|
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
|
-
|
|
27937
|
-
|
|
27938
|
-
|
|
27973
|
+
const status = response.meta?.TransactionResult;
|
|
27974
|
+
if (status === XrplTxStatus.SUCCESS) {
|
|
27975
|
+
return status;
|
|
27939
27976
|
}
|
|
27940
|
-
|
|
27941
|
-
|
|
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
|
-
|
|
27948
|
-
|
|
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
|
-
|
|
28098
|
-
return
|
|
28099
|
-
|
|
28100
|
-
|
|
28101
|
-
|
|
28102
|
-
|
|
28103
|
-
|
|
28104
|
-
|
|
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
|
-
*
|
|
28007
|
+
* Returns the balance of the user in the native XRP token
|
|
28008
|
+
* formatted as a string
|
|
28246
28009
|
*/
|
|
28247
|
-
|
|
28248
|
-
|
|
28249
|
-
|
|
28250
|
-
|
|
28251
|
-
|
|
28252
|
-
|
|
28253
|
-
|
|
28254
|
-
|
|
28255
|
-
|
|
28256
|
-
|
|
28257
|
-
|
|
28258
|
-
|
|
28259
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
28300
|
-
|
|
28301
|
-
|
|
28302
|
-
|
|
28303
|
-
|
|
28304
|
-
|
|
28305
|
-
|
|
28306
|
-
|
|
28307
|
-
|
|
28308
|
-
|
|
28309
|
-
|
|
28310
|
-
|
|
28311
|
-
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
|
|
28315
|
-
|
|
28316
|
-
|
|
28317
|
-
|
|
28318
|
-
|
|
28319
|
-
|
|
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
|
-
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
return
|
|
28341
|
-
|
|
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
|
|
28347
|
-
|
|
28348
|
-
const
|
|
28349
|
-
|
|
28350
|
-
|
|
28351
|
-
}
|
|
28352
|
-
const
|
|
28353
|
-
|
|
28354
|
-
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28359
|
-
|
|
28360
|
-
|
|
28361
|
-
|
|
28362
|
-
|
|
28363
|
-
|
|
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
|
-
|
|
30112
|
-
|
|
30113
|
-
|
|
30114
|
-
|
|
30115
|
-
|
|
30116
|
-
|
|
30117
|
-
|
|
30118
|
-
|
|
30119
|
-
|
|
30120
|
-
|
|
30121
|
-
|
|
30122
|
-
|
|
30123
|
-
|
|
30124
|
-
|
|
30125
|
-
|
|
30126
|
-
|
|
30127
|
-
|
|
30128
|
-
|
|
30129
|
-
|
|
30130
|
-
|
|
30131
|
-
|
|
30132
|
-
|
|
30133
|
-
|
|
30134
|
-
|
|
30135
|
-
|
|
30136
|
-
|
|
30137
|
-
|
|
30138
|
-
|
|
30139
|
-
|
|
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
|
-
|
|
30142
|
-
|
|
30143
|
-
|
|
30144
|
-
|
|
30145
|
-
|
|
30146
|
-
|
|
30147
|
-
|
|
30148
|
-
|
|
30149
|
-
|
|
30150
|
-
|
|
30151
|
-
|
|
30152
|
-
|
|
30153
|
-
|
|
30154
|
-
|
|
30155
|
-
|
|
30156
|
-
|
|
30157
|
-
|
|
30158
|
-
|
|
30159
|
-
|
|
30160
|
-
|
|
30161
|
-
|
|
30162
|
-
|
|
30163
|
-
|
|
30164
|
-
|
|
30165
|
-
|
|
30166
|
-
|
|
30167
|
-
|
|
30168
|
-
|
|
30169
|
-
|
|
30170
|
-
|
|
30171
|
-
|
|
30172
|
-
}
|
|
30173
|
-
|
|
30174
|
-
|
|
30175
|
-
|
|
30176
|
-
|
|
30177
|
-
|
|
30178
|
-
|
|
30179
|
-
|
|
30180
|
-
|
|
30181
|
-
|
|
30182
|
-
const
|
|
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
|
|
29997
|
+
return isEvmSignerReady;
|
|
30188
29998
|
case ChainType.COSMOS:
|
|
30189
|
-
return
|
|
29999
|
+
return isCosmosSignerReady;
|
|
30190
30000
|
case ChainType.BTC:
|
|
30191
|
-
return
|
|
30001
|
+
return isBitcoinSignerReady;
|
|
30192
30002
|
case ChainType.SOLANA:
|
|
30193
|
-
return
|
|
30003
|
+
return isSolanaSignerReady;
|
|
30194
30004
|
case ChainType.SUI:
|
|
30195
|
-
return
|
|
30005
|
+
return isSuiSignerReady;
|
|
30196
30006
|
case ChainType.XRPL:
|
|
30197
|
-
return
|
|
30007
|
+
return isXrplSignerReady;
|
|
30198
30008
|
case ChainType.STELLAR:
|
|
30199
|
-
return
|
|
30009
|
+
return isStellarSignerReady;
|
|
30200
30010
|
}
|
|
30201
30011
|
}, [
|
|
30202
30012
|
chain?.chainType,
|
|
30203
|
-
|
|
30204
|
-
|
|
30205
|
-
|
|
30206
|
-
|
|
30207
|
-
|
|
30208
|
-
|
|
30209
|
-
|
|
30013
|
+
isEvmSignerReady,
|
|
30014
|
+
isCosmosSignerReady,
|
|
30015
|
+
isBitcoinSignerReady,
|
|
30016
|
+
isSolanaSignerReady,
|
|
30017
|
+
isSuiSignerReady,
|
|
30018
|
+
isXrplSignerReady,
|
|
30019
|
+
isStellarSignerReady,
|
|
30210
30020
|
]);
|
|
30211
|
-
return {
|
|
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
|
|
30215
|
-
const
|
|
30216
|
-
|
|
30217
|
-
|
|
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
|
-
|
|
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
|
|
30906
|
-
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
30911
|
-
|
|
30912
|
-
|
|
30913
|
-
|
|
30914
|
-
}
|
|
30915
|
-
|
|
30916
|
-
|
|
30917
|
-
|
|
30918
|
-
|
|
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
|
|
30997
|
-
|
|
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
|
-
|
|
31000
|
-
totalFeesInNativeTokenPlusRatio,
|
|
31001
|
-
nativeTokenBalanceFromChainWei,
|
|
31148
|
+
networkFeesWei,
|
|
31002
31149
|
});
|
|
31003
|
-
const
|
|
31004
|
-
|
|
31005
|
-
|
|
31006
|
-
|
|
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
|
-
|
|
31183
|
+
fromTokenPaysNetworkFee: chainFeeParams?.fromTokenPaysNetworkFee ?? false,
|
|
31035
31184
|
totalNativeFees,
|
|
31036
31185
|
totalFeesInNativeTokenPlusRatio,
|
|
31037
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
31185
|
-
|
|
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
|
-
|
|
31189
|
-
|
|
31190
|
-
|
|
31191
|
-
|
|
31192
|
-
|
|
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 || !
|
|
31347
|
+
if (!token?.address || !estimatedGas)
|
|
31348
|
+
return undefined;
|
|
31349
|
+
if (!chainFeeParams)
|
|
31204
31350
|
return undefined;
|
|
31205
|
-
const
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31209
|
-
|
|
31210
|
-
|
|
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
|
-
|
|
31215
|
-
|
|
31216
|
-
|
|
31217
|
-
|
|
31218
|
-
token
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
32312
|
-
|
|
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
|
-
|
|
32385
|
-
|
|
32386
|
-
|
|
32387
|
-
|
|
32388
|
-
|
|
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
|
-
|
|
32547
|
+
fromBalanceFormatted,
|
|
32392
32548
|
slippageFormatted,
|
|
32393
32549
|
totalWithRefundEstimate,
|
|
32394
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
36196
|
-
|
|
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
|
|
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,
|
|
36911
|
-
//# sourceMappingURL=index-
|
|
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
|