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