@shapeshiftoss/swap-widget 0.0.2 → 0.2.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/LICENSE.md +21 -0
- package/README.md +18 -11
- package/package.json +77 -28
- package/Dockerfile +0 -87
- package/dist/assets/PhArrowCircleDown-B305t-Sh.js +0 -14
- package/dist/assets/PhArrowClockwise-CJPxQhr_.js +0 -14
- package/dist/assets/PhArrowDown-C4hT9BVu.js +0 -14
- package/dist/assets/PhArrowLeft-Way4Cu-r.js +0 -14
- package/dist/assets/PhArrowRight-Cp5ZME0F.js +0 -14
- package/dist/assets/PhArrowSquareOut-NnrK69c5.js +0 -14
- package/dist/assets/PhArrowUp-Dph6j8rm.js +0 -14
- package/dist/assets/PhArrowUpRight-BpJjRRRh.js +0 -14
- package/dist/assets/PhArrowsClockwise-CFUT8X7R.js +0 -14
- package/dist/assets/PhArrowsDownUp-BjBI4ckC.js +0 -14
- package/dist/assets/PhArrowsLeftRight-CuLpbKRk.js +0 -14
- package/dist/assets/PhBank-Dchr4XQJ.js +0 -14
- package/dist/assets/PhBrowser-dUu2TrC1.js +0 -14
- package/dist/assets/PhCaretDown-78IuKU3V.js +0 -14
- package/dist/assets/PhCaretLeft-_aiyH7n1.js +0 -14
- package/dist/assets/PhCaretRight-8zJQEuDX.js +0 -14
- package/dist/assets/PhCaretUp-CiCxKWwN.js +0 -14
- package/dist/assets/PhCheck-CcADx8br.js +0 -14
- package/dist/assets/PhCircleHalf-BYzSzd2h.js +0 -14
- package/dist/assets/PhClock-UItiXeJq.js +0 -14
- package/dist/assets/PhCompass-CUy3uA7t.js +0 -14
- package/dist/assets/PhCopy-C-PDgSlZ.js +0 -14
- package/dist/assets/PhCreditCard-CWRaUT6F.js +0 -14
- package/dist/assets/PhCurrencyDollar-Cqla3AXT.js +0 -14
- package/dist/assets/PhDesktop-BBIPrYLl.js +0 -14
- package/dist/assets/PhDeviceMobile-BdsPaATg.js +0 -14
- package/dist/assets/PhDotsThree-BMXCQl-0.js +0 -14
- package/dist/assets/PhEnvelope-yUsis6yU.js +0 -14
- package/dist/assets/PhFunnelSimple-Ba7BbWTp.js +0 -14
- package/dist/assets/PhGlobe-DgLxBk5U.js +0 -14
- package/dist/assets/PhIdentificationCard-Czjmq9Z3.js +0 -14
- package/dist/assets/PhImage-BAJ_erz6.js +0 -14
- package/dist/assets/PhInfo-Cr4DhVUE.js +0 -14
- package/dist/assets/PhLightbulb-BX_7duTr.js +0 -14
- package/dist/assets/PhMagnifyingGlass-Mygfryvz.js +0 -14
- package/dist/assets/PhPaperPlaneRight-BeuCA660.js +0 -14
- package/dist/assets/PhPlus-BMjcHjsT.js +0 -14
- package/dist/assets/PhPower-CGffGmdb.js +0 -14
- package/dist/assets/PhPuzzlePiece-wm_GpVSi.js +0 -14
- package/dist/assets/PhQrCode-DRwRzXCH.js +0 -14
- package/dist/assets/PhQuestion-M09j2U0T.js +0 -14
- package/dist/assets/PhQuestionMark-BP9EMB6h.js +0 -14
- package/dist/assets/PhSealCheck-BfG80yKn.js +0 -14
- package/dist/assets/PhSignOut-C5YOWlPT.js +0 -14
- package/dist/assets/PhSpinner-BXooDYzU.js +0 -14
- package/dist/assets/PhTrash-Biq6rmmL.js +0 -14
- package/dist/assets/PhUser-CAgZSpGe.js +0 -14
- package/dist/assets/PhVault-l2PHF38a.js +0 -14
- package/dist/assets/PhWallet-w25D16It.js +0 -14
- package/dist/assets/PhWarning-DPEydIPw.js +0 -14
- package/dist/assets/PhWarningCircle-BqjT745H.js +0 -14
- package/dist/assets/PhX-s-SmVExa.js +0 -14
- package/dist/assets/SwapController-If0bFrNc.js +0 -1
- package/dist/assets/ccip-BBB7uCdL.js +0 -1
- package/dist/assets/ccip-CkkdfKKI.js +0 -1
- package/dist/assets/data-capture-D4gAy-Yc.js +0 -242
- package/dist/assets/email-B1AJehis.js +0 -90
- package/dist/assets/embedded-wallet-Q6DQopDk.js +0 -410
- package/dist/assets/features-B6JAPAFb.js +0 -5
- package/dist/assets/index-5jd8RPN9.js +0 -7428
- package/dist/assets/index-B4kNtSTk.js +0 -1080
- package/dist/assets/index-B753eAob.js +0 -1
- package/dist/assets/index-BZoLTv77.js +0 -3
- package/dist/assets/index-Bcw9UURX.js +0 -3
- package/dist/assets/index-BkrV-ahK.js +0 -2
- package/dist/assets/index-CRQzQ_up.js +0 -9
- package/dist/assets/index-CSW0Gt5y.js +0 -132
- package/dist/assets/index-CZ4jTIsk.js +0 -138
- package/dist/assets/index-Cwa8SB3h.js +0 -61
- package/dist/assets/index-DEwQgT4r.js +0 -78
- package/dist/assets/index-DVfQiQ1d.js +0 -1
- package/dist/assets/index-cV3UdaMs.css +0 -1
- package/dist/assets/index-hAmu622O.js +0 -43
- package/dist/assets/onramp-XcPNCLRU.js +0 -422
- package/dist/assets/pay-with-exchange-BeHt4OF4.js +0 -280
- package/dist/assets/property-C9JG5tag.js +0 -27
- package/dist/assets/receive-7ff4he2S.js +0 -131
- package/dist/assets/send-CkMBIRXT.js +0 -554
- package/dist/assets/socials-DmmxuLrP.js +0 -250
- package/dist/assets/swaps-IHAYRQ0x.js +0 -1050
- package/dist/assets/transactions-9Cxdk7o9.js +0 -16
- package/dist/assets/v4-BOvFkHkt.js +0 -1
- package/dist/assets/w3m-modal-kJzFnBfB.js +0 -891
- package/dist/assets/wallet-standard-Dv8LMoUB.js +0 -1
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +0 -11
- package/dist/icon-192x192.png +0 -0
- package/dist/icon-512x512.png +0 -0
- package/dist/index.html +0 -33
- package/index.html +0 -32
- package/public/favicon.png +0 -0
- package/public/favicon.svg +0 -11
- package/public/icon-192x192.png +0 -0
- package/public/icon-512x512.png +0 -0
- package/railway.toml +0 -10
- package/src/api/client.ts +0 -95
- package/src/components/AddressInputModal.css +0 -173
- package/src/components/AddressInputModal.tsx +0 -250
- package/src/components/ApprovalStep.tsx +0 -92
- package/src/components/ExecutionStep.tsx +0 -27
- package/src/components/InputStep.tsx +0 -431
- package/src/components/QuoteSelector.css +0 -146
- package/src/components/QuoteSelector.tsx +0 -137
- package/src/components/QuotesModal.css +0 -250
- package/src/components/QuotesModal.tsx +0 -182
- package/src/components/SettingsModal.css +0 -145
- package/src/components/SettingsModal.tsx +0 -180
- package/src/components/StatusStep.tsx +0 -139
- package/src/components/SwapWidget.css +0 -713
- package/src/components/SwapWidget.tsx +0 -607
- package/src/components/TokenSelectModal.css +0 -438
- package/src/components/TokenSelectModal.tsx +0 -487
- package/src/components/WalletProvider.tsx +0 -92
- package/src/config/appkit.ts +0 -104
- package/src/config/wagmi.ts +0 -27
- package/src/constants/chains.ts +0 -72
- package/src/constants/defaults.ts +0 -28
- package/src/constants/swappers.ts +0 -48
- package/src/constants/viemChains.ts +0 -69
- package/src/contexts/SwapWalletContext.tsx +0 -25
- package/src/demo/App.css +0 -458
- package/src/demo/App.tsx +0 -481
- package/src/demo/main.tsx +0 -25
- package/src/hooks/useAssets.ts +0 -180
- package/src/hooks/useBalances.ts +0 -822
- package/src/hooks/useBitcoinSigning.ts +0 -276
- package/src/hooks/useMarketData.ts +0 -169
- package/src/hooks/useSolanaSigning.ts +0 -275
- package/src/hooks/useStatusPolling.ts +0 -137
- package/src/hooks/useSwapApproval.ts +0 -106
- package/src/hooks/useSwapDisplayValues.ts +0 -157
- package/src/hooks/useSwapExecution.ts +0 -199
- package/src/hooks/useSwapHandlers.ts +0 -119
- package/src/hooks/useSwapQuote.ts +0 -71
- package/src/hooks/useSwapQuoting.ts +0 -102
- package/src/hooks/useSwapRates.ts +0 -61
- package/src/index.ts +0 -43
- package/src/machines/SwapMachineContext.ts +0 -5
- package/src/machines/__tests__/guards.test.ts +0 -228
- package/src/machines/__tests__/setup.test.ts +0 -7
- package/src/machines/__tests__/swapMachine.test.ts +0 -544
- package/src/machines/__tests__/types.test.ts +0 -124
- package/src/machines/guards.ts +0 -33
- package/src/machines/swapMachine.ts +0 -288
- package/src/machines/types.ts +0 -54
- package/src/services/transactionStatus.ts +0 -322
- package/src/types/index.ts +0 -361
- package/src/utils/addressValidation.ts +0 -201
- package/src/utils/redirect.ts +0 -45
- package/src/vite-env.d.ts +0 -10
- package/tsconfig.json +0 -23
- package/tsconfig.node.json +0 -10
- package/vite.config.ts +0 -101
- package/vitest.config.ts +0 -18
package/src/hooks/useBalances.ts
DELETED
|
@@ -1,822 +0,0 @@
|
|
|
1
|
-
import { useAppKitConnection } from '@reown/appkit-adapter-solana/react'
|
|
2
|
-
import { ASSET_NAMESPACE, CHAIN_NAMESPACE, fromAssetId } from '@shapeshiftoss/caip'
|
|
3
|
-
import { Connection, PublicKey } from '@solana/web3.js'
|
|
4
|
-
import { useQueries, useQueryClient } from '@tanstack/react-query'
|
|
5
|
-
import { getBalance, readContract } from '@wagmi/core'
|
|
6
|
-
import PQueue from 'p-queue'
|
|
7
|
-
import { useCallback, useMemo } from 'react'
|
|
8
|
-
import { erc20Abi } from 'viem'
|
|
9
|
-
import { useConfig } from 'wagmi'
|
|
10
|
-
|
|
11
|
-
import type { SupportedChainId } from '../config/wagmi'
|
|
12
|
-
import type { AssetId } from '../types'
|
|
13
|
-
import { formatAmount, getChainType, UTXO_CHAIN_IDS } from '../types'
|
|
14
|
-
|
|
15
|
-
const CONCURRENCY_LIMIT = 5
|
|
16
|
-
const DELAY_BETWEEN_BATCHES_MS = 50
|
|
17
|
-
|
|
18
|
-
const balanceQueue = new PQueue({
|
|
19
|
-
concurrency: CONCURRENCY_LIMIT,
|
|
20
|
-
interval: DELAY_BETWEEN_BATCHES_MS,
|
|
21
|
-
intervalCap: CONCURRENCY_LIMIT,
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
type BalanceResult = {
|
|
25
|
-
assetId: AssetId
|
|
26
|
-
balance: string
|
|
27
|
-
balanceFormatted: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
type BalancesMap = Record<AssetId, BalanceResult>
|
|
31
|
-
|
|
32
|
-
type ParsedAssetEvm = {
|
|
33
|
-
chainType: 'evm'
|
|
34
|
-
evmChainId: number
|
|
35
|
-
tokenAddress?: `0x${string}`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type ParsedAssetUtxo = {
|
|
39
|
-
chainType: 'utxo'
|
|
40
|
-
chainReference: string
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
type ParsedAssetSolana = {
|
|
44
|
-
chainType: 'solana'
|
|
45
|
-
tokenAddress?: string
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
type ParsedAsset = ParsedAssetEvm | ParsedAssetUtxo | ParsedAssetSolana | null
|
|
49
|
-
|
|
50
|
-
const MEMPOOL_API_BASE = 'https://mempool.space/api'
|
|
51
|
-
const SOLANA_PUBLIC_RPC = 'https://api.mainnet-beta.solana.com'
|
|
52
|
-
|
|
53
|
-
const parseAssetIdMultiChain = (assetId: AssetId): ParsedAsset => {
|
|
54
|
-
try {
|
|
55
|
-
const { chainNamespace, chainReference, assetNamespace, assetReference } = fromAssetId(assetId)
|
|
56
|
-
const chainType = getChainType(assetId.split('/')[0] as string)
|
|
57
|
-
|
|
58
|
-
if (chainType === 'evm' && chainNamespace === CHAIN_NAMESPACE.Evm) {
|
|
59
|
-
const evmChainId = Number(chainReference)
|
|
60
|
-
if (assetNamespace === ASSET_NAMESPACE.erc20) {
|
|
61
|
-
return {
|
|
62
|
-
chainType: 'evm',
|
|
63
|
-
evmChainId,
|
|
64
|
-
tokenAddress: assetReference as `0x${string}`,
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return { chainType: 'evm', evmChainId }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (chainType === 'utxo' && chainNamespace === CHAIN_NAMESPACE.Utxo) {
|
|
71
|
-
return { chainType: 'utxo', chainReference }
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (chainType === 'solana' && chainNamespace === CHAIN_NAMESPACE.Solana) {
|
|
75
|
-
if (assetNamespace === ASSET_NAMESPACE.splToken) {
|
|
76
|
-
return { chainType: 'solana', tokenAddress: assetReference }
|
|
77
|
-
}
|
|
78
|
-
return { chainType: 'solana' }
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return null
|
|
82
|
-
} catch {
|
|
83
|
-
return null
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const parseAssetId = (
|
|
88
|
-
assetId: AssetId,
|
|
89
|
-
): { chainId: number; tokenAddress?: `0x${string}` } | null => {
|
|
90
|
-
try {
|
|
91
|
-
const { chainNamespace, chainReference, assetNamespace, assetReference } = fromAssetId(assetId)
|
|
92
|
-
|
|
93
|
-
if (chainNamespace !== CHAIN_NAMESPACE.Evm) return null
|
|
94
|
-
|
|
95
|
-
const evmChainId = Number(chainReference)
|
|
96
|
-
|
|
97
|
-
if (assetNamespace === ASSET_NAMESPACE.erc20) {
|
|
98
|
-
return {
|
|
99
|
-
chainId: evmChainId,
|
|
100
|
-
tokenAddress: assetReference as `0x${string}`,
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return { chainId: evmChainId }
|
|
105
|
-
} catch {
|
|
106
|
-
return null
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const fetchBitcoinBalance = async (
|
|
111
|
-
address: string,
|
|
112
|
-
network: 'mainnet' | 'testnet' = 'mainnet',
|
|
113
|
-
): Promise<string> => {
|
|
114
|
-
const baseUrl = network === 'testnet' ? 'https://mempool.space/testnet/api' : MEMPOOL_API_BASE
|
|
115
|
-
|
|
116
|
-
const response = await fetch(`${baseUrl}/address/${address}`)
|
|
117
|
-
if (!response.ok) {
|
|
118
|
-
throw new Error(`Failed to fetch Bitcoin balance: ${response.status}`)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const data = await response.json()
|
|
122
|
-
const confirmedFunded = data.chain_stats?.funded_txo_sum ?? 0
|
|
123
|
-
const confirmedSpent = data.chain_stats?.spent_txo_sum ?? 0
|
|
124
|
-
const mempoolFunded = data.mempool_stats?.funded_txo_sum ?? 0
|
|
125
|
-
const mempoolSpent = data.mempool_stats?.spent_txo_sum ?? 0
|
|
126
|
-
const totalBalance = confirmedFunded - confirmedSpent + (mempoolFunded - mempoolSpent)
|
|
127
|
-
|
|
128
|
-
return totalBalance.toString()
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export const useEvmBalances = (
|
|
132
|
-
address: string | undefined,
|
|
133
|
-
assetIds: AssetId[],
|
|
134
|
-
assetPrecisions: Record<AssetId, number>,
|
|
135
|
-
) => {
|
|
136
|
-
const config = useConfig()
|
|
137
|
-
|
|
138
|
-
const parsedAssets = useMemo(() => {
|
|
139
|
-
return assetIds
|
|
140
|
-
.map(assetId => {
|
|
141
|
-
const parsed = parseAssetId(assetId)
|
|
142
|
-
if (!parsed) return null
|
|
143
|
-
return {
|
|
144
|
-
assetId,
|
|
145
|
-
chainId: parsed.chainId as SupportedChainId,
|
|
146
|
-
tokenAddress: parsed.tokenAddress,
|
|
147
|
-
precision: assetPrecisions[assetId] ?? 18,
|
|
148
|
-
isNative: !parsed.tokenAddress,
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
.filter(Boolean) as {
|
|
152
|
-
assetId: AssetId
|
|
153
|
-
chainId: SupportedChainId
|
|
154
|
-
tokenAddress?: `0x${string}`
|
|
155
|
-
precision: number
|
|
156
|
-
isNative: boolean
|
|
157
|
-
}[]
|
|
158
|
-
}, [assetIds, assetPrecisions])
|
|
159
|
-
|
|
160
|
-
const nativeAssets = useMemo(() => parsedAssets.filter(a => a.isNative), [parsedAssets])
|
|
161
|
-
|
|
162
|
-
const erc20Assets = useMemo(() => parsedAssets.filter(a => !a.isNative), [parsedAssets])
|
|
163
|
-
|
|
164
|
-
const nativeQueries = useQueries({
|
|
165
|
-
queries: nativeAssets.map(asset => ({
|
|
166
|
-
queryKey: ['nativeBalance', address, asset.chainId],
|
|
167
|
-
queryFn: () => {
|
|
168
|
-
if (!address) return Promise.resolve(null)
|
|
169
|
-
return balanceQueue.add(async () => {
|
|
170
|
-
try {
|
|
171
|
-
const result = await getBalance(config, {
|
|
172
|
-
address: address as `0x${string}`,
|
|
173
|
-
// @ts-ignore - swap-widget supports more chains than main app's wagmi type registration
|
|
174
|
-
chainId: asset.chainId,
|
|
175
|
-
})
|
|
176
|
-
return {
|
|
177
|
-
assetId: asset.assetId,
|
|
178
|
-
balance: result.value.toString(),
|
|
179
|
-
precision: asset.precision,
|
|
180
|
-
}
|
|
181
|
-
} catch {
|
|
182
|
-
return null
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
},
|
|
186
|
-
enabled: !!address,
|
|
187
|
-
staleTime: 60_000,
|
|
188
|
-
refetchOnWindowFocus: false,
|
|
189
|
-
})),
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
const erc20Queries = useQueries({
|
|
193
|
-
queries: erc20Assets.map(asset => ({
|
|
194
|
-
queryKey: ['erc20Balance', address, asset.chainId, asset.tokenAddress],
|
|
195
|
-
queryFn: () => {
|
|
196
|
-
if (!address) return Promise.resolve(null)
|
|
197
|
-
return balanceQueue.add(async () => {
|
|
198
|
-
try {
|
|
199
|
-
if (!asset.tokenAddress) return null
|
|
200
|
-
const result = await readContract(config, {
|
|
201
|
-
address: asset.tokenAddress,
|
|
202
|
-
abi: erc20Abi,
|
|
203
|
-
functionName: 'balanceOf',
|
|
204
|
-
args: [address as `0x${string}`],
|
|
205
|
-
// @ts-ignore - swap-widget supports more chains than main app's wagmi type registration
|
|
206
|
-
chainId: asset.chainId,
|
|
207
|
-
})
|
|
208
|
-
return {
|
|
209
|
-
assetId: asset.assetId,
|
|
210
|
-
balance: (result as bigint).toString(),
|
|
211
|
-
precision: asset.precision,
|
|
212
|
-
}
|
|
213
|
-
} catch {
|
|
214
|
-
return null
|
|
215
|
-
}
|
|
216
|
-
})
|
|
217
|
-
},
|
|
218
|
-
enabled: !!address,
|
|
219
|
-
staleTime: 60_000,
|
|
220
|
-
refetchOnWindowFocus: false,
|
|
221
|
-
})),
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
const isErc20Loading = erc20Queries.some(q => q.isLoading)
|
|
225
|
-
|
|
226
|
-
const balances = useMemo((): BalancesMap => {
|
|
227
|
-
const result: BalancesMap = {}
|
|
228
|
-
|
|
229
|
-
nativeQueries.forEach(query => {
|
|
230
|
-
if (query.data) {
|
|
231
|
-
const { assetId, balance, precision } = query.data
|
|
232
|
-
result[assetId] = {
|
|
233
|
-
assetId,
|
|
234
|
-
balance,
|
|
235
|
-
balanceFormatted: formatAmount(balance, precision),
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
erc20Queries.forEach(query => {
|
|
241
|
-
if (query.data) {
|
|
242
|
-
const { assetId, balance, precision } = query.data
|
|
243
|
-
result[assetId] = {
|
|
244
|
-
assetId,
|
|
245
|
-
balance,
|
|
246
|
-
balanceFormatted: formatAmount(balance, precision),
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
return result
|
|
252
|
-
}, [nativeQueries, erc20Queries])
|
|
253
|
-
|
|
254
|
-
const isLoading = nativeQueries.some(q => q.isLoading) || isErc20Loading
|
|
255
|
-
|
|
256
|
-
const loadingAssetIds = useMemo(() => {
|
|
257
|
-
const loading = new Set<AssetId>()
|
|
258
|
-
nativeQueries.forEach((query, index) => {
|
|
259
|
-
if (query.isLoading) {
|
|
260
|
-
loading.add(nativeAssets[index].assetId)
|
|
261
|
-
}
|
|
262
|
-
})
|
|
263
|
-
erc20Queries.forEach((query, index) => {
|
|
264
|
-
if (query.isLoading) {
|
|
265
|
-
loading.add(erc20Assets[index].assetId)
|
|
266
|
-
}
|
|
267
|
-
})
|
|
268
|
-
return loading
|
|
269
|
-
}, [nativeQueries, nativeAssets, erc20Queries, erc20Assets])
|
|
270
|
-
|
|
271
|
-
return { data: balances, isLoading, loadingAssetIds }
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export const useBitcoinBalance = (
|
|
275
|
-
address: string | undefined,
|
|
276
|
-
assetId: AssetId | undefined,
|
|
277
|
-
precision: number = 8,
|
|
278
|
-
) => {
|
|
279
|
-
const parsed = assetId ? parseAssetIdMultiChain(assetId) : null
|
|
280
|
-
const isUtxo = parsed?.chainType === 'utxo'
|
|
281
|
-
|
|
282
|
-
const query = useQueries({
|
|
283
|
-
queries: [
|
|
284
|
-
{
|
|
285
|
-
queryKey: ['utxoBalance', address, assetId],
|
|
286
|
-
queryFn: async () => {
|
|
287
|
-
if (!address || !assetId || !isUtxo) return null
|
|
288
|
-
try {
|
|
289
|
-
const balance = await fetchBitcoinBalance(address)
|
|
290
|
-
return {
|
|
291
|
-
assetId,
|
|
292
|
-
balance,
|
|
293
|
-
precision,
|
|
294
|
-
}
|
|
295
|
-
} catch {
|
|
296
|
-
return null
|
|
297
|
-
}
|
|
298
|
-
},
|
|
299
|
-
enabled: !!address && !!assetId && isUtxo,
|
|
300
|
-
staleTime: 60_000,
|
|
301
|
-
refetchOnWindowFocus: false,
|
|
302
|
-
},
|
|
303
|
-
],
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
return useMemo(() => {
|
|
307
|
-
const queryResult = query[0]
|
|
308
|
-
if (!queryResult?.data || !assetId) {
|
|
309
|
-
return {
|
|
310
|
-
data: undefined,
|
|
311
|
-
isLoading: queryResult?.isLoading ?? false,
|
|
312
|
-
refetch: queryResult?.refetch,
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const { balance } = queryResult.data
|
|
317
|
-
return {
|
|
318
|
-
data: {
|
|
319
|
-
assetId,
|
|
320
|
-
balance,
|
|
321
|
-
balanceFormatted: formatAmount(balance, precision),
|
|
322
|
-
},
|
|
323
|
-
isLoading: queryResult.isLoading,
|
|
324
|
-
refetch: queryResult.refetch,
|
|
325
|
-
}
|
|
326
|
-
}, [query, assetId, precision])
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
export const useSolanaBalance = (
|
|
330
|
-
address: string | undefined,
|
|
331
|
-
assetId: AssetId | undefined,
|
|
332
|
-
precision: number = 9,
|
|
333
|
-
) => {
|
|
334
|
-
const { connection: walletConnection } = useAppKitConnection()
|
|
335
|
-
const parsed = assetId ? parseAssetIdMultiChain(assetId) : null
|
|
336
|
-
const isSolana = parsed?.chainType === 'solana'
|
|
337
|
-
const isNative = isSolana && !('tokenAddress' in parsed && parsed.tokenAddress)
|
|
338
|
-
const tokenAddress = isSolana && 'tokenAddress' in parsed ? parsed.tokenAddress : undefined
|
|
339
|
-
|
|
340
|
-
const query = useQueries({
|
|
341
|
-
queries: [
|
|
342
|
-
{
|
|
343
|
-
queryKey: ['solanaBalance', address, assetId, isNative],
|
|
344
|
-
queryFn: async () => {
|
|
345
|
-
if (!address || !assetId || !isSolana) return null
|
|
346
|
-
|
|
347
|
-
const connection = walletConnection ?? new Connection(SOLANA_PUBLIC_RPC, 'confirmed')
|
|
348
|
-
|
|
349
|
-
try {
|
|
350
|
-
const pubKey = new PublicKey(address)
|
|
351
|
-
|
|
352
|
-
if (isNative) {
|
|
353
|
-
const balance = await connection.getBalance(pubKey)
|
|
354
|
-
return {
|
|
355
|
-
assetId,
|
|
356
|
-
balance: balance.toString(),
|
|
357
|
-
precision,
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (tokenAddress) {
|
|
362
|
-
const tokenPubKey = new PublicKey(tokenAddress)
|
|
363
|
-
const tokenAccounts = await connection.getTokenAccountsByOwner(pubKey, {
|
|
364
|
-
mint: tokenPubKey,
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
if (tokenAccounts.value.length === 0) {
|
|
368
|
-
return {
|
|
369
|
-
assetId,
|
|
370
|
-
balance: '0',
|
|
371
|
-
precision,
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const accountInfo = tokenAccounts.value[0].account.data
|
|
376
|
-
const balance = accountInfo.slice(64, 72).readBigUInt64LE()
|
|
377
|
-
return {
|
|
378
|
-
assetId,
|
|
379
|
-
balance: balance.toString(),
|
|
380
|
-
precision,
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return null
|
|
385
|
-
} catch {
|
|
386
|
-
return null
|
|
387
|
-
}
|
|
388
|
-
},
|
|
389
|
-
enabled: !!address && !!assetId && isSolana,
|
|
390
|
-
staleTime: 30_000,
|
|
391
|
-
refetchOnWindowFocus: false,
|
|
392
|
-
},
|
|
393
|
-
],
|
|
394
|
-
})
|
|
395
|
-
|
|
396
|
-
return useMemo(() => {
|
|
397
|
-
const queryResult = query[0]
|
|
398
|
-
if (!queryResult?.data || !assetId) {
|
|
399
|
-
return {
|
|
400
|
-
data: undefined,
|
|
401
|
-
isLoading: queryResult?.isLoading ?? false,
|
|
402
|
-
refetch: queryResult?.refetch,
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const { balance } = queryResult.data
|
|
407
|
-
return {
|
|
408
|
-
data: {
|
|
409
|
-
assetId,
|
|
410
|
-
balance,
|
|
411
|
-
balanceFormatted: formatAmount(balance, precision),
|
|
412
|
-
},
|
|
413
|
-
isLoading: queryResult.isLoading,
|
|
414
|
-
refetch: queryResult.refetch,
|
|
415
|
-
}
|
|
416
|
-
}, [query, assetId, precision])
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
export const useMultiChainBalance = (
|
|
420
|
-
evmAddress: string | undefined,
|
|
421
|
-
utxoAddress: string | undefined,
|
|
422
|
-
solanaAddress: string | undefined,
|
|
423
|
-
assetId: AssetId | undefined,
|
|
424
|
-
precision: number = 18,
|
|
425
|
-
) => {
|
|
426
|
-
const parsed = assetId ? parseAssetIdMultiChain(assetId) : null
|
|
427
|
-
const chainType = parsed?.chainType ?? 'other'
|
|
428
|
-
const config = useConfig()
|
|
429
|
-
|
|
430
|
-
const addressForChain =
|
|
431
|
-
chainType === 'evm'
|
|
432
|
-
? evmAddress
|
|
433
|
-
: chainType === 'utxo'
|
|
434
|
-
? utxoAddress
|
|
435
|
-
: chainType === 'solana'
|
|
436
|
-
? solanaAddress
|
|
437
|
-
: undefined
|
|
438
|
-
|
|
439
|
-
const evmParsed = chainType === 'evm' && parsed?.chainType === 'evm' ? parsed : null
|
|
440
|
-
const isErc20 = evmParsed && evmParsed.tokenAddress
|
|
441
|
-
|
|
442
|
-
const evmQuery = useQueries({
|
|
443
|
-
queries: [
|
|
444
|
-
{
|
|
445
|
-
queryKey: [
|
|
446
|
-
'singleEvmBalance',
|
|
447
|
-
evmAddress,
|
|
448
|
-
assetId,
|
|
449
|
-
evmParsed?.evmChainId,
|
|
450
|
-
evmParsed?.tokenAddress,
|
|
451
|
-
],
|
|
452
|
-
queryFn: async () => {
|
|
453
|
-
if (!evmAddress || !assetId || !evmParsed) return null
|
|
454
|
-
try {
|
|
455
|
-
if (isErc20 && evmParsed.tokenAddress) {
|
|
456
|
-
const result = await readContract(config, {
|
|
457
|
-
address: evmParsed.tokenAddress,
|
|
458
|
-
abi: erc20Abi,
|
|
459
|
-
functionName: 'balanceOf',
|
|
460
|
-
args: [evmAddress as `0x${string}`],
|
|
461
|
-
chainId: evmParsed.evmChainId,
|
|
462
|
-
})
|
|
463
|
-
return {
|
|
464
|
-
assetId,
|
|
465
|
-
balance: (result as bigint).toString(),
|
|
466
|
-
precision,
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
const result = await getBalance(config, {
|
|
470
|
-
address: evmAddress as `0x${string}`,
|
|
471
|
-
// @ts-ignore
|
|
472
|
-
chainId: evmParsed.evmChainId,
|
|
473
|
-
})
|
|
474
|
-
return {
|
|
475
|
-
assetId,
|
|
476
|
-
balance: result.value.toString(),
|
|
477
|
-
precision,
|
|
478
|
-
}
|
|
479
|
-
} catch {
|
|
480
|
-
return null
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
enabled: chainType === 'evm' && !!evmAddress && !!assetId,
|
|
484
|
-
staleTime: 60_000,
|
|
485
|
-
refetchOnWindowFocus: false,
|
|
486
|
-
},
|
|
487
|
-
],
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
const evmBalance = useMemo(() => {
|
|
491
|
-
const queryResult = evmQuery[0]
|
|
492
|
-
if (!queryResult?.data || !assetId) {
|
|
493
|
-
return {
|
|
494
|
-
data: undefined,
|
|
495
|
-
isLoading: queryResult?.isLoading ?? false,
|
|
496
|
-
refetch: queryResult?.refetch,
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const { balance } = queryResult.data
|
|
501
|
-
return {
|
|
502
|
-
data: {
|
|
503
|
-
assetId,
|
|
504
|
-
balance,
|
|
505
|
-
balanceFormatted: formatAmount(balance, precision),
|
|
506
|
-
},
|
|
507
|
-
isLoading: queryResult.isLoading,
|
|
508
|
-
refetch: queryResult.refetch,
|
|
509
|
-
}
|
|
510
|
-
}, [evmQuery, assetId, precision])
|
|
511
|
-
|
|
512
|
-
const utxoBalance = useBitcoinBalance(
|
|
513
|
-
chainType === 'utxo' ? addressForChain : undefined,
|
|
514
|
-
chainType === 'utxo' ? assetId : undefined,
|
|
515
|
-
precision,
|
|
516
|
-
)
|
|
517
|
-
|
|
518
|
-
const solanaBalance = useSolanaBalance(
|
|
519
|
-
chainType === 'solana' ? addressForChain : undefined,
|
|
520
|
-
chainType === 'solana' ? assetId : undefined,
|
|
521
|
-
precision,
|
|
522
|
-
)
|
|
523
|
-
|
|
524
|
-
return useMemo(() => {
|
|
525
|
-
switch (chainType) {
|
|
526
|
-
case 'evm':
|
|
527
|
-
return evmBalance
|
|
528
|
-
case 'utxo':
|
|
529
|
-
return utxoBalance
|
|
530
|
-
case 'solana':
|
|
531
|
-
return solanaBalance
|
|
532
|
-
default:
|
|
533
|
-
return { data: undefined, isLoading: false, refetch: undefined }
|
|
534
|
-
}
|
|
535
|
-
}, [chainType, evmBalance, utxoBalance, solanaBalance])
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
export const useMultiChainBalances = (
|
|
539
|
-
evmAddress: string | undefined,
|
|
540
|
-
utxoAddress: string | undefined,
|
|
541
|
-
solanaAddress: string | undefined,
|
|
542
|
-
assetIds: AssetId[],
|
|
543
|
-
assetPrecisions: Record<AssetId, number>,
|
|
544
|
-
) => {
|
|
545
|
-
const config = useConfig()
|
|
546
|
-
const { connection: walletConnection } = useAppKitConnection()
|
|
547
|
-
const queryClient = useQueryClient()
|
|
548
|
-
|
|
549
|
-
const groupedAssets = useMemo(() => {
|
|
550
|
-
const evm: {
|
|
551
|
-
assetId: AssetId
|
|
552
|
-
chainId: number
|
|
553
|
-
tokenAddress?: `0x${string}`
|
|
554
|
-
precision: number
|
|
555
|
-
}[] = []
|
|
556
|
-
const utxo: { assetId: AssetId; precision: number }[] = []
|
|
557
|
-
const solana: { assetId: AssetId; tokenAddress?: string; precision: number }[] = []
|
|
558
|
-
|
|
559
|
-
assetIds.forEach(assetId => {
|
|
560
|
-
const parsed = parseAssetIdMultiChain(assetId)
|
|
561
|
-
const precision = assetPrecisions[assetId] ?? 18
|
|
562
|
-
|
|
563
|
-
if (parsed?.chainType === 'evm') {
|
|
564
|
-
evm.push({
|
|
565
|
-
assetId,
|
|
566
|
-
chainId: parsed.evmChainId,
|
|
567
|
-
tokenAddress: parsed.tokenAddress,
|
|
568
|
-
precision,
|
|
569
|
-
})
|
|
570
|
-
} else if (
|
|
571
|
-
parsed?.chainType === 'utxo' &&
|
|
572
|
-
parsed.chainReference === UTXO_CHAIN_IDS.bitcoin.split(':')[1]
|
|
573
|
-
) {
|
|
574
|
-
utxo.push({ assetId, precision })
|
|
575
|
-
} else if (parsed?.chainType === 'solana') {
|
|
576
|
-
solana.push({
|
|
577
|
-
assetId,
|
|
578
|
-
tokenAddress: parsed.tokenAddress,
|
|
579
|
-
precision,
|
|
580
|
-
})
|
|
581
|
-
}
|
|
582
|
-
})
|
|
583
|
-
|
|
584
|
-
return { evm, utxo, solana }
|
|
585
|
-
}, [assetIds, assetPrecisions])
|
|
586
|
-
|
|
587
|
-
const evmQueries = useQueries({
|
|
588
|
-
queries: groupedAssets.evm.map(asset => ({
|
|
589
|
-
queryKey: ['multiChainBalance', 'evm', evmAddress, asset.chainId, asset.tokenAddress],
|
|
590
|
-
queryFn: async () => {
|
|
591
|
-
if (!evmAddress) return null
|
|
592
|
-
try {
|
|
593
|
-
if (asset.tokenAddress) {
|
|
594
|
-
const result = await readContract(config, {
|
|
595
|
-
address: asset.tokenAddress,
|
|
596
|
-
abi: erc20Abi,
|
|
597
|
-
functionName: 'balanceOf',
|
|
598
|
-
args: [evmAddress as `0x${string}`],
|
|
599
|
-
// @ts-ignore - swap-widget supports more chains than main app's wagmi type registration
|
|
600
|
-
chainId: asset.chainId,
|
|
601
|
-
})
|
|
602
|
-
return {
|
|
603
|
-
assetId: asset.assetId,
|
|
604
|
-
balance: (result as bigint).toString(),
|
|
605
|
-
precision: asset.precision,
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
const result = await getBalance(config, {
|
|
609
|
-
address: evmAddress as `0x${string}`,
|
|
610
|
-
// @ts-ignore - swap-widget supports more chains than main app's wagmi type registration
|
|
611
|
-
chainId: asset.chainId,
|
|
612
|
-
})
|
|
613
|
-
return {
|
|
614
|
-
assetId: asset.assetId,
|
|
615
|
-
balance: result.value.toString(),
|
|
616
|
-
precision: asset.precision,
|
|
617
|
-
}
|
|
618
|
-
} catch {
|
|
619
|
-
return null
|
|
620
|
-
}
|
|
621
|
-
},
|
|
622
|
-
enabled: !!evmAddress,
|
|
623
|
-
staleTime: 60_000,
|
|
624
|
-
refetchOnWindowFocus: false,
|
|
625
|
-
})),
|
|
626
|
-
})
|
|
627
|
-
|
|
628
|
-
const utxoQueries = useQueries({
|
|
629
|
-
queries: groupedAssets.utxo.map(asset => ({
|
|
630
|
-
queryKey: ['multiChainBalance', 'utxo', utxoAddress, asset.assetId],
|
|
631
|
-
queryFn: async () => {
|
|
632
|
-
if (!utxoAddress) return null
|
|
633
|
-
try {
|
|
634
|
-
const balance = await fetchBitcoinBalance(utxoAddress)
|
|
635
|
-
return {
|
|
636
|
-
assetId: asset.assetId,
|
|
637
|
-
balance,
|
|
638
|
-
precision: asset.precision,
|
|
639
|
-
}
|
|
640
|
-
} catch {
|
|
641
|
-
return null
|
|
642
|
-
}
|
|
643
|
-
},
|
|
644
|
-
enabled: !!utxoAddress,
|
|
645
|
-
staleTime: 60_000,
|
|
646
|
-
refetchOnWindowFocus: false,
|
|
647
|
-
})),
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
const solanaQueries = useQueries({
|
|
651
|
-
queries: groupedAssets.solana.map(asset => ({
|
|
652
|
-
queryKey: ['multiChainBalance', 'solana', solanaAddress, asset.assetId, asset.tokenAddress],
|
|
653
|
-
queryFn: async () => {
|
|
654
|
-
if (!solanaAddress) return null
|
|
655
|
-
|
|
656
|
-
const connection = walletConnection ?? new Connection(SOLANA_PUBLIC_RPC, 'confirmed')
|
|
657
|
-
|
|
658
|
-
try {
|
|
659
|
-
const pubKey = new PublicKey(solanaAddress)
|
|
660
|
-
|
|
661
|
-
if (!asset.tokenAddress) {
|
|
662
|
-
const balance = await connection.getBalance(pubKey)
|
|
663
|
-
return {
|
|
664
|
-
assetId: asset.assetId,
|
|
665
|
-
balance: balance.toString(),
|
|
666
|
-
precision: asset.precision,
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
const tokenPubKey = new PublicKey(asset.tokenAddress)
|
|
671
|
-
const tokenAccounts = await connection.getTokenAccountsByOwner(pubKey, {
|
|
672
|
-
mint: tokenPubKey,
|
|
673
|
-
})
|
|
674
|
-
|
|
675
|
-
if (tokenAccounts.value.length === 0) {
|
|
676
|
-
return {
|
|
677
|
-
assetId: asset.assetId,
|
|
678
|
-
balance: '0',
|
|
679
|
-
precision: asset.precision,
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const accountInfo = tokenAccounts.value[0].account.data
|
|
684
|
-
const balance = accountInfo.slice(64, 72).readBigUInt64LE()
|
|
685
|
-
return {
|
|
686
|
-
assetId: asset.assetId,
|
|
687
|
-
balance: balance.toString(),
|
|
688
|
-
precision: asset.precision,
|
|
689
|
-
}
|
|
690
|
-
} catch {
|
|
691
|
-
return null
|
|
692
|
-
}
|
|
693
|
-
},
|
|
694
|
-
enabled: !!solanaAddress,
|
|
695
|
-
staleTime: 30_000,
|
|
696
|
-
refetchOnWindowFocus: false,
|
|
697
|
-
})),
|
|
698
|
-
})
|
|
699
|
-
|
|
700
|
-
const balances = useMemo((): BalancesMap => {
|
|
701
|
-
const result: BalancesMap = {}
|
|
702
|
-
|
|
703
|
-
;[...evmQueries, ...utxoQueries, ...solanaQueries].forEach(query => {
|
|
704
|
-
if (query.data) {
|
|
705
|
-
const { assetId, balance, precision } = query.data
|
|
706
|
-
const formatted = formatAmount(balance, precision)
|
|
707
|
-
result[assetId] = {
|
|
708
|
-
assetId,
|
|
709
|
-
balance,
|
|
710
|
-
balanceFormatted: formatted,
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
})
|
|
714
|
-
|
|
715
|
-
return result
|
|
716
|
-
}, [evmQueries, utxoQueries, solanaQueries])
|
|
717
|
-
|
|
718
|
-
const isLoading =
|
|
719
|
-
evmQueries.some(q => q.isLoading) ||
|
|
720
|
-
utxoQueries.some(q => q.isLoading) ||
|
|
721
|
-
solanaQueries.some(q => q.isLoading)
|
|
722
|
-
|
|
723
|
-
const loadingAssetIds = useMemo(() => {
|
|
724
|
-
const loading = new Set<AssetId>()
|
|
725
|
-
|
|
726
|
-
evmQueries.forEach((query, index) => {
|
|
727
|
-
if (query.isLoading) {
|
|
728
|
-
loading.add(groupedAssets.evm[index].assetId)
|
|
729
|
-
}
|
|
730
|
-
})
|
|
731
|
-
utxoQueries.forEach((query, index) => {
|
|
732
|
-
if (query.isLoading) {
|
|
733
|
-
loading.add(groupedAssets.utxo[index].assetId)
|
|
734
|
-
}
|
|
735
|
-
})
|
|
736
|
-
solanaQueries.forEach((query, index) => {
|
|
737
|
-
if (query.isLoading) {
|
|
738
|
-
loading.add(groupedAssets.solana[index].assetId)
|
|
739
|
-
}
|
|
740
|
-
})
|
|
741
|
-
|
|
742
|
-
return loading
|
|
743
|
-
}, [evmQueries, utxoQueries, solanaQueries, groupedAssets])
|
|
744
|
-
|
|
745
|
-
const refetch = useCallback(() => {
|
|
746
|
-
queryClient.invalidateQueries({
|
|
747
|
-
predicate: query => {
|
|
748
|
-
const key = query.queryKey
|
|
749
|
-
return (
|
|
750
|
-
(Array.isArray(key) && key[0] === 'multiChainBalance') ||
|
|
751
|
-
key[0] === 'nativeBalance' ||
|
|
752
|
-
key[0] === 'erc20Balance' ||
|
|
753
|
-
key[0] === 'utxoBalance' ||
|
|
754
|
-
key[0] === 'solanaBalance'
|
|
755
|
-
)
|
|
756
|
-
},
|
|
757
|
-
})
|
|
758
|
-
}, [queryClient])
|
|
759
|
-
|
|
760
|
-
const refetchSpecific = useCallback(
|
|
761
|
-
(targetAssetIds: AssetId[]) => {
|
|
762
|
-
queryClient.invalidateQueries({
|
|
763
|
-
predicate: query => {
|
|
764
|
-
const key = query.queryKey as unknown[]
|
|
765
|
-
if (!Array.isArray(key) || key[0] !== 'multiChainBalance') return false
|
|
766
|
-
|
|
767
|
-
return targetAssetIds.some(assetId => {
|
|
768
|
-
const evmAsset = groupedAssets.evm.find(a => a.assetId === assetId)
|
|
769
|
-
if (evmAsset) {
|
|
770
|
-
const expectedKey = [
|
|
771
|
-
'multiChainBalance',
|
|
772
|
-
'evm',
|
|
773
|
-
evmAddress,
|
|
774
|
-
evmAsset.chainId,
|
|
775
|
-
evmAsset.tokenAddress,
|
|
776
|
-
]
|
|
777
|
-
if (
|
|
778
|
-
key.length === expectedKey.length &&
|
|
779
|
-
key.every((val, idx) => val === expectedKey[idx])
|
|
780
|
-
) {
|
|
781
|
-
return true
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
const utxoAsset = groupedAssets.utxo.find(a => a.assetId === assetId)
|
|
786
|
-
if (utxoAsset) {
|
|
787
|
-
const expectedKey = ['multiChainBalance', 'utxo', utxoAddress, assetId]
|
|
788
|
-
if (
|
|
789
|
-
key.length === expectedKey.length &&
|
|
790
|
-
key.every((val, idx) => val === expectedKey[idx])
|
|
791
|
-
) {
|
|
792
|
-
return true
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
const solanaAsset = groupedAssets.solana.find(a => a.assetId === assetId)
|
|
797
|
-
if (solanaAsset) {
|
|
798
|
-
const expectedKey = [
|
|
799
|
-
'multiChainBalance',
|
|
800
|
-
'solana',
|
|
801
|
-
solanaAddress,
|
|
802
|
-
assetId,
|
|
803
|
-
solanaAsset.tokenAddress,
|
|
804
|
-
]
|
|
805
|
-
if (
|
|
806
|
-
key.length === expectedKey.length &&
|
|
807
|
-
key.every((val, idx) => val === expectedKey[idx])
|
|
808
|
-
) {
|
|
809
|
-
return true
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
return false
|
|
814
|
-
})
|
|
815
|
-
},
|
|
816
|
-
})
|
|
817
|
-
},
|
|
818
|
-
[queryClient, groupedAssets, evmAddress, utxoAddress, solanaAddress],
|
|
819
|
-
)
|
|
820
|
-
|
|
821
|
-
return { data: balances, isLoading, loadingAssetIds, refetch, refetchSpecific }
|
|
822
|
-
}
|