@shapeshiftoss/swap-widget 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/index.d.ts +233 -0
  2. package/dist/index.js +63612 -0
  3. package/dist/style.css +1 -0
  4. package/package.json +69 -18
  5. package/Dockerfile +0 -87
  6. package/dist/assets/PhArrowCircleDown-B305t-Sh.js +0 -14
  7. package/dist/assets/PhArrowClockwise-CJPxQhr_.js +0 -14
  8. package/dist/assets/PhArrowDown-C4hT9BVu.js +0 -14
  9. package/dist/assets/PhArrowLeft-Way4Cu-r.js +0 -14
  10. package/dist/assets/PhArrowRight-Cp5ZME0F.js +0 -14
  11. package/dist/assets/PhArrowSquareOut-NnrK69c5.js +0 -14
  12. package/dist/assets/PhArrowUp-Dph6j8rm.js +0 -14
  13. package/dist/assets/PhArrowUpRight-BpJjRRRh.js +0 -14
  14. package/dist/assets/PhArrowsClockwise-CFUT8X7R.js +0 -14
  15. package/dist/assets/PhArrowsDownUp-BjBI4ckC.js +0 -14
  16. package/dist/assets/PhArrowsLeftRight-CuLpbKRk.js +0 -14
  17. package/dist/assets/PhBank-Dchr4XQJ.js +0 -14
  18. package/dist/assets/PhBrowser-dUu2TrC1.js +0 -14
  19. package/dist/assets/PhCaretDown-78IuKU3V.js +0 -14
  20. package/dist/assets/PhCaretLeft-_aiyH7n1.js +0 -14
  21. package/dist/assets/PhCaretRight-8zJQEuDX.js +0 -14
  22. package/dist/assets/PhCaretUp-CiCxKWwN.js +0 -14
  23. package/dist/assets/PhCheck-CcADx8br.js +0 -14
  24. package/dist/assets/PhCircleHalf-BYzSzd2h.js +0 -14
  25. package/dist/assets/PhClock-UItiXeJq.js +0 -14
  26. package/dist/assets/PhCompass-CUy3uA7t.js +0 -14
  27. package/dist/assets/PhCopy-C-PDgSlZ.js +0 -14
  28. package/dist/assets/PhCreditCard-CWRaUT6F.js +0 -14
  29. package/dist/assets/PhCurrencyDollar-Cqla3AXT.js +0 -14
  30. package/dist/assets/PhDesktop-BBIPrYLl.js +0 -14
  31. package/dist/assets/PhDeviceMobile-BdsPaATg.js +0 -14
  32. package/dist/assets/PhDotsThree-BMXCQl-0.js +0 -14
  33. package/dist/assets/PhEnvelope-yUsis6yU.js +0 -14
  34. package/dist/assets/PhFunnelSimple-Ba7BbWTp.js +0 -14
  35. package/dist/assets/PhGlobe-DgLxBk5U.js +0 -14
  36. package/dist/assets/PhIdentificationCard-Czjmq9Z3.js +0 -14
  37. package/dist/assets/PhImage-BAJ_erz6.js +0 -14
  38. package/dist/assets/PhInfo-Cr4DhVUE.js +0 -14
  39. package/dist/assets/PhLightbulb-BX_7duTr.js +0 -14
  40. package/dist/assets/PhMagnifyingGlass-Mygfryvz.js +0 -14
  41. package/dist/assets/PhPaperPlaneRight-BeuCA660.js +0 -14
  42. package/dist/assets/PhPlus-BMjcHjsT.js +0 -14
  43. package/dist/assets/PhPower-CGffGmdb.js +0 -14
  44. package/dist/assets/PhPuzzlePiece-wm_GpVSi.js +0 -14
  45. package/dist/assets/PhQrCode-DRwRzXCH.js +0 -14
  46. package/dist/assets/PhQuestion-M09j2U0T.js +0 -14
  47. package/dist/assets/PhQuestionMark-BP9EMB6h.js +0 -14
  48. package/dist/assets/PhSealCheck-BfG80yKn.js +0 -14
  49. package/dist/assets/PhSignOut-C5YOWlPT.js +0 -14
  50. package/dist/assets/PhSpinner-BXooDYzU.js +0 -14
  51. package/dist/assets/PhTrash-Biq6rmmL.js +0 -14
  52. package/dist/assets/PhUser-CAgZSpGe.js +0 -14
  53. package/dist/assets/PhVault-l2PHF38a.js +0 -14
  54. package/dist/assets/PhWallet-w25D16It.js +0 -14
  55. package/dist/assets/PhWarning-DPEydIPw.js +0 -14
  56. package/dist/assets/PhWarningCircle-BqjT745H.js +0 -14
  57. package/dist/assets/PhX-s-SmVExa.js +0 -14
  58. package/dist/assets/SwapController-If0bFrNc.js +0 -1
  59. package/dist/assets/ccip-BBB7uCdL.js +0 -1
  60. package/dist/assets/ccip-CkkdfKKI.js +0 -1
  61. package/dist/assets/data-capture-D4gAy-Yc.js +0 -242
  62. package/dist/assets/email-B1AJehis.js +0 -90
  63. package/dist/assets/embedded-wallet-Q6DQopDk.js +0 -410
  64. package/dist/assets/features-B6JAPAFb.js +0 -5
  65. package/dist/assets/index-5jd8RPN9.js +0 -7428
  66. package/dist/assets/index-B4kNtSTk.js +0 -1080
  67. package/dist/assets/index-B753eAob.js +0 -1
  68. package/dist/assets/index-BZoLTv77.js +0 -3
  69. package/dist/assets/index-Bcw9UURX.js +0 -3
  70. package/dist/assets/index-BkrV-ahK.js +0 -2
  71. package/dist/assets/index-CRQzQ_up.js +0 -9
  72. package/dist/assets/index-CSW0Gt5y.js +0 -132
  73. package/dist/assets/index-CZ4jTIsk.js +0 -138
  74. package/dist/assets/index-Cwa8SB3h.js +0 -61
  75. package/dist/assets/index-DEwQgT4r.js +0 -78
  76. package/dist/assets/index-DVfQiQ1d.js +0 -1
  77. package/dist/assets/index-cV3UdaMs.css +0 -1
  78. package/dist/assets/index-hAmu622O.js +0 -43
  79. package/dist/assets/onramp-XcPNCLRU.js +0 -422
  80. package/dist/assets/pay-with-exchange-BeHt4OF4.js +0 -280
  81. package/dist/assets/property-C9JG5tag.js +0 -27
  82. package/dist/assets/receive-7ff4he2S.js +0 -131
  83. package/dist/assets/send-CkMBIRXT.js +0 -554
  84. package/dist/assets/socials-DmmxuLrP.js +0 -250
  85. package/dist/assets/swaps-IHAYRQ0x.js +0 -1050
  86. package/dist/assets/transactions-9Cxdk7o9.js +0 -16
  87. package/dist/assets/v4-BOvFkHkt.js +0 -1
  88. package/dist/assets/w3m-modal-kJzFnBfB.js +0 -891
  89. package/dist/assets/wallet-standard-Dv8LMoUB.js +0 -1
  90. package/dist/favicon.png +0 -0
  91. package/dist/favicon.svg +0 -11
  92. package/dist/icon-192x192.png +0 -0
  93. package/dist/icon-512x512.png +0 -0
  94. package/dist/index.html +0 -33
  95. package/index.html +0 -32
  96. package/public/favicon.png +0 -0
  97. package/public/favicon.svg +0 -11
  98. package/public/icon-192x192.png +0 -0
  99. package/public/icon-512x512.png +0 -0
  100. package/railway.toml +0 -10
  101. package/src/api/client.ts +0 -95
  102. package/src/components/AddressInputModal.css +0 -173
  103. package/src/components/AddressInputModal.tsx +0 -250
  104. package/src/components/ApprovalStep.tsx +0 -92
  105. package/src/components/ExecutionStep.tsx +0 -27
  106. package/src/components/InputStep.tsx +0 -431
  107. package/src/components/QuoteSelector.css +0 -146
  108. package/src/components/QuoteSelector.tsx +0 -137
  109. package/src/components/QuotesModal.css +0 -250
  110. package/src/components/QuotesModal.tsx +0 -182
  111. package/src/components/SettingsModal.css +0 -145
  112. package/src/components/SettingsModal.tsx +0 -180
  113. package/src/components/StatusStep.tsx +0 -139
  114. package/src/components/SwapWidget.css +0 -713
  115. package/src/components/SwapWidget.tsx +0 -607
  116. package/src/components/TokenSelectModal.css +0 -438
  117. package/src/components/TokenSelectModal.tsx +0 -487
  118. package/src/components/WalletProvider.tsx +0 -92
  119. package/src/config/appkit.ts +0 -104
  120. package/src/config/wagmi.ts +0 -27
  121. package/src/constants/chains.ts +0 -72
  122. package/src/constants/defaults.ts +0 -28
  123. package/src/constants/swappers.ts +0 -48
  124. package/src/constants/viemChains.ts +0 -69
  125. package/src/contexts/SwapWalletContext.tsx +0 -25
  126. package/src/demo/App.css +0 -458
  127. package/src/demo/App.tsx +0 -481
  128. package/src/demo/main.tsx +0 -25
  129. package/src/hooks/useAssets.ts +0 -180
  130. package/src/hooks/useBalances.ts +0 -822
  131. package/src/hooks/useBitcoinSigning.ts +0 -276
  132. package/src/hooks/useMarketData.ts +0 -169
  133. package/src/hooks/useSolanaSigning.ts +0 -275
  134. package/src/hooks/useStatusPolling.ts +0 -137
  135. package/src/hooks/useSwapApproval.ts +0 -106
  136. package/src/hooks/useSwapDisplayValues.ts +0 -157
  137. package/src/hooks/useSwapExecution.ts +0 -199
  138. package/src/hooks/useSwapHandlers.ts +0 -119
  139. package/src/hooks/useSwapQuote.ts +0 -71
  140. package/src/hooks/useSwapQuoting.ts +0 -102
  141. package/src/hooks/useSwapRates.ts +0 -61
  142. package/src/index.ts +0 -43
  143. package/src/machines/SwapMachineContext.ts +0 -5
  144. package/src/machines/__tests__/guards.test.ts +0 -228
  145. package/src/machines/__tests__/setup.test.ts +0 -7
  146. package/src/machines/__tests__/swapMachine.test.ts +0 -544
  147. package/src/machines/__tests__/types.test.ts +0 -124
  148. package/src/machines/guards.ts +0 -33
  149. package/src/machines/swapMachine.ts +0 -288
  150. package/src/machines/types.ts +0 -54
  151. package/src/services/transactionStatus.ts +0 -322
  152. package/src/types/index.ts +0 -361
  153. package/src/utils/addressValidation.ts +0 -201
  154. package/src/utils/redirect.ts +0 -45
  155. package/src/vite-env.d.ts +0 -10
  156. package/tsconfig.json +0 -23
  157. package/tsconfig.node.json +0 -10
  158. package/vite.config.ts +0 -101
  159. package/vitest.config.ts +0 -18
@@ -1,487 +0,0 @@
1
- import './TokenSelectModal.css'
2
-
3
- import { bnOrZero } from '@shapeshiftoss/utils'
4
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
5
- import { Virtuoso } from 'react-virtuoso'
6
-
7
- import type { ChainInfo } from '../hooks/useAssets'
8
- import { useAssets, useChains } from '../hooks/useAssets'
9
- import { useMultiChainBalances } from '../hooks/useBalances'
10
- import { useBitcoinSigning } from '../hooks/useBitcoinSigning'
11
- import { useAllMarketData } from '../hooks/useMarketData'
12
- import { useSolanaSigning } from '../hooks/useSolanaSigning'
13
- import type { Asset, AssetId, ChainId } from '../types'
14
-
15
- const VISIBLE_BUFFER = 10
16
-
17
- const useLockBodyScroll = (isLocked: boolean) => {
18
- useEffect(() => {
19
- if (!isLocked) return
20
- const originalOverflow = document.body.style.overflow
21
- document.body.style.overflow = 'hidden'
22
- return () => {
23
- document.body.style.overflow = originalOverflow
24
- }
25
- }, [isLocked])
26
- }
27
-
28
- type TokenSelectModalProps = {
29
- isOpen: boolean
30
- onClose: () => void
31
- onSelect: (asset: Asset) => void
32
- disabledAssetIds?: string[]
33
- disabledChainIds?: ChainId[]
34
- allowedChainIds?: ChainId[]
35
- allowedAssetIds?: AssetId[]
36
- walletAddress?: string
37
- currentAssetIds?: AssetId[]
38
- }
39
-
40
- const isNativeAsset = (assetId: string): boolean => {
41
- return assetId.includes('/slip44:') || assetId.endsWith('/native')
42
- }
43
-
44
- const scoreAsset = (asset: Asset, query: string): number => {
45
- const lowerQuery = query.toLowerCase()
46
- const symbolLower = asset.symbol.toLowerCase()
47
- const nameLower = asset.name.toLowerCase()
48
-
49
- let score = 0
50
-
51
- if (symbolLower === lowerQuery) score += 1000
52
- else if (symbolLower.startsWith(lowerQuery)) score += 500
53
- else if (symbolLower.includes(lowerQuery)) score += 100
54
-
55
- if (nameLower === lowerQuery) score += 800
56
- else if (nameLower.startsWith(lowerQuery)) score += 300
57
- else if (nameLower.includes(lowerQuery)) score += 50
58
-
59
- if (isNativeAsset(asset.assetId)) score += 200
60
-
61
- return score
62
- }
63
-
64
- export const TokenSelectModal = ({
65
- isOpen,
66
- onClose,
67
- onSelect,
68
- disabledAssetIds = [],
69
- disabledChainIds = [],
70
- allowedChainIds,
71
- allowedAssetIds,
72
- walletAddress,
73
- currentAssetIds = [],
74
- }: TokenSelectModalProps) => {
75
- useLockBodyScroll(isOpen)
76
- const [searchQuery, setSearchQuery] = useState('')
77
- const [chainSearchQuery, setChainSearchQuery] = useState('')
78
- const [selectedChainId, setSelectedChainId] = useState<ChainId | null>(null)
79
- const [visibleRange, setVisibleRange] = useState({
80
- startIndex: 0,
81
- endIndex: 20,
82
- })
83
-
84
- const { data: allAssets, isLoading: isLoadingAssets } = useAssets()
85
- const { data: chains, isLoading: isLoadingChains } = useChains()
86
-
87
- const chainInfoMap = useMemo(() => {
88
- const map = new Map<ChainId, ChainInfo>()
89
- for (const chain of chains) {
90
- map.set(chain.chainId, chain)
91
- }
92
- return map
93
- }, [chains])
94
-
95
- const allowedAssetChainIds = useMemo(() => {
96
- if (!allowedAssetIds || allowedAssetIds.length === 0) return undefined
97
- const chainIds = new Set<ChainId>()
98
- for (const asset of allAssets) {
99
- if (allowedAssetIds.includes(asset.assetId)) {
100
- chainIds.add(asset.chainId)
101
- }
102
- }
103
- return Array.from(chainIds)
104
- }, [allowedAssetIds, allAssets])
105
-
106
- const filteredChains = useMemo(() => {
107
- let enabledChains = chains.filter(chain => !disabledChainIds.includes(chain.chainId))
108
-
109
- if (allowedChainIds && allowedChainIds.length > 0) {
110
- enabledChains = enabledChains.filter(chain => allowedChainIds.includes(chain.chainId))
111
- }
112
-
113
- if (allowedAssetChainIds) {
114
- enabledChains = enabledChains.filter(chain => allowedAssetChainIds.includes(chain.chainId))
115
- }
116
-
117
- if (!chainSearchQuery.trim()) return enabledChains
118
-
119
- const lowerQuery = chainSearchQuery.toLowerCase()
120
- return enabledChains.filter(chain => chain.name.toLowerCase().includes(lowerQuery))
121
- }, [chains, chainSearchQuery, disabledChainIds, allowedChainIds, allowedAssetChainIds])
122
-
123
- const filteredAssets = useMemo(() => {
124
- let assets = allAssets.filter(
125
- asset =>
126
- !disabledAssetIds.includes(asset.assetId) && !disabledChainIds.includes(asset.chainId),
127
- )
128
-
129
- if (allowedAssetIds && allowedAssetIds.length > 0) {
130
- assets = assets.filter(asset => allowedAssetIds.includes(asset.assetId))
131
- }
132
-
133
- if (allowedChainIds && allowedChainIds.length > 0) {
134
- assets = assets.filter(asset => allowedChainIds.includes(asset.chainId))
135
- }
136
-
137
- if (selectedChainId) {
138
- assets = assets.filter(asset => asset.chainId === selectedChainId)
139
- }
140
-
141
- if (!searchQuery.trim()) {
142
- const natives = assets.filter(a => isNativeAsset(a.assetId))
143
- const others = assets
144
- .filter(a => !isNativeAsset(a.assetId))
145
- .slice(0, Math.max(50 - natives.length, 30))
146
- return [...natives, ...others]
147
- }
148
-
149
- const lowerQuery = searchQuery.toLowerCase()
150
- return assets
151
- .filter(
152
- asset =>
153
- asset.symbol.toLowerCase().includes(lowerQuery) ||
154
- asset.name.toLowerCase().includes(lowerQuery) ||
155
- asset.assetId.toLowerCase().includes(lowerQuery),
156
- )
157
- .map(asset => ({ asset, score: scoreAsset(asset, searchQuery) }))
158
- .sort((a, b) => b.score - a.score)
159
- .slice(0, 100)
160
- .map(item => item.asset)
161
- }, [
162
- allAssets,
163
- selectedChainId,
164
- searchQuery,
165
- disabledAssetIds,
166
- disabledChainIds,
167
- allowedAssetIds,
168
- allowedChainIds,
169
- ])
170
-
171
- const { address: bitcoinAddress } = useBitcoinSigning()
172
- const { address: solanaAddress } = useSolanaSigning()
173
-
174
- const initialAssetPrecisions = useMemo(() => {
175
- const precisions: Record<AssetId, number> = {}
176
- for (const asset of filteredAssets.slice(0, 30)) {
177
- precisions[asset.assetId] = asset.precision
178
- }
179
- return precisions
180
- }, [filteredAssets])
181
-
182
- const initialAssetIds = useMemo(
183
- () => filteredAssets.slice(0, 30).map(a => a.assetId),
184
- [filteredAssets],
185
- )
186
-
187
- const {
188
- data: balances,
189
- loadingAssetIds,
190
- refetchSpecific,
191
- } = useMultiChainBalances(
192
- walletAddress,
193
- bitcoinAddress,
194
- solanaAddress,
195
- initialAssetIds,
196
- initialAssetPrecisions,
197
- )
198
-
199
- useEffect(() => {
200
- if (isOpen && currentAssetIds.length > 0) {
201
- refetchSpecific?.(currentAssetIds)
202
- }
203
- }, [isOpen, currentAssetIds, refetchSpecific])
204
-
205
- const { data: marketData } = useAllMarketData()
206
-
207
- const balanceSortDoneRef = useRef(false)
208
- const sortedAssetsRef = useRef<Asset[]>(filteredAssets)
209
- const prevFilteredRef = useRef(filteredAssets)
210
-
211
- const sortedAssets = useMemo(() => {
212
- const filterChanged = filteredAssets !== prevFilteredRef.current
213
- if (filterChanged) {
214
- prevFilteredRef.current = filteredAssets
215
- balanceSortDoneRef.current = false
216
- }
217
-
218
- if (balanceSortDoneRef.current) {
219
- return sortedAssetsRef.current
220
- }
221
-
222
- if (!balances || Object.keys(balances).length === 0) {
223
- sortedAssetsRef.current = filteredAssets
224
- return filteredAssets
225
- }
226
-
227
- const withBalance: { asset: Asset; fiatValue: number }[] = []
228
- const withoutBalance: Asset[] = []
229
-
230
- for (const asset of filteredAssets) {
231
- const balance = balances[asset.assetId]
232
- if (balance && balance.balance !== '0') {
233
- const price = marketData?.[asset.assetId]?.price
234
- const fiatValue = price
235
- ? bnOrZero(balance.balance)
236
- .div(bnOrZero(10).pow(asset.precision))
237
- .times(bnOrZero(price))
238
- .toNumber()
239
- : 0
240
- withBalance.push({ asset, fiatValue })
241
- } else {
242
- withoutBalance.push(asset)
243
- }
244
- }
245
-
246
- withBalance.sort((a, b) => b.fiatValue - a.fiatValue)
247
-
248
- const result = [...withBalance.map(w => w.asset), ...withoutBalance]
249
- balanceSortDoneRef.current = true
250
- sortedAssetsRef.current = result
251
- return result
252
- }, [filteredAssets, balances, marketData])
253
-
254
- const visibleRangeAssetIds = useMemo(() => {
255
- const start = Math.max(0, visibleRange.startIndex - VISIBLE_BUFFER)
256
- const end = Math.min(sortedAssets.length, visibleRange.endIndex + VISIBLE_BUFFER)
257
- return sortedAssets.slice(start, end).map(a => a.assetId)
258
- }, [sortedAssets, visibleRange])
259
-
260
- useEffect(() => {
261
- if (visibleRangeAssetIds.length > 0) {
262
- refetchSpecific?.(visibleRangeAssetIds)
263
- }
264
- }, [visibleRangeAssetIds, refetchSpecific])
265
-
266
- const handleAssetSelect = useCallback(
267
- (asset: Asset) => {
268
- onSelect(asset)
269
- onClose()
270
- setSearchQuery('')
271
- setSelectedChainId(null)
272
- },
273
- [onSelect, onClose],
274
- )
275
-
276
- const handleChainSelect = useCallback((chainId: ChainId | null) => {
277
- setSelectedChainId(chainId)
278
- }, [])
279
-
280
- const handleBackdropClick = useCallback(
281
- (e: React.MouseEvent) => {
282
- if (e.target === e.currentTarget) {
283
- onClose()
284
- }
285
- },
286
- [onClose],
287
- )
288
-
289
- if (!isOpen) return null
290
-
291
- const isLoading = isLoadingAssets || isLoadingChains
292
-
293
- return (
294
- // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
295
- <div
296
- className='ssw-modal-backdrop'
297
- onClick={handleBackdropClick}
298
- onKeyDown={e => e.key === 'Escape' && onClose()}
299
- role='dialog'
300
- aria-modal='true'
301
- aria-labelledby='token-modal-title'
302
- >
303
- <div className='ssw-modal'>
304
- <div className='ssw-modal-header'>
305
- <h2 id='token-modal-title' className='ssw-modal-title'>
306
- Select Token
307
- </h2>
308
- <button className='ssw-modal-close' onClick={onClose} type='button'>
309
- <svg
310
- width='20'
311
- height='20'
312
- viewBox='0 0 24 24'
313
- fill='none'
314
- stroke='currentColor'
315
- strokeWidth='2'
316
- >
317
- <path d='M18 6L6 18M6 6l12 12' />
318
- </svg>
319
- </button>
320
- </div>
321
-
322
- <div className='ssw-modal-content'>
323
- <div className='ssw-chain-sidebar'>
324
- <div className='ssw-search-wrapper'>
325
- <svg
326
- className='ssw-search-icon'
327
- width='16'
328
- height='16'
329
- viewBox='0 0 24 24'
330
- fill='none'
331
- stroke='currentColor'
332
- strokeWidth='2'
333
- >
334
- <circle cx='11' cy='11' r='8' />
335
- <path d='m21 21-4.35-4.35' />
336
- </svg>
337
- <input
338
- type='text'
339
- className='ssw-chain-search'
340
- placeholder='Search chains'
341
- value={chainSearchQuery}
342
- onChange={e => setChainSearchQuery(e.target.value)}
343
- />
344
- </div>
345
-
346
- <div className='ssw-chain-list'>
347
- <button
348
- className={`ssw-chain-item ${selectedChainId === null ? 'ssw-selected' : ''}`}
349
- onClick={() => handleChainSelect(null)}
350
- type='button'
351
- >
352
- <span className='ssw-chain-name'>All Chains</span>
353
- </button>
354
-
355
- {filteredChains.map(chain => (
356
- <button
357
- key={chain.chainId}
358
- className={`ssw-chain-item ${
359
- selectedChainId === chain.chainId ? 'ssw-selected' : ''
360
- }`}
361
- onClick={() => handleChainSelect(chain.chainId)}
362
- type='button'
363
- >
364
- {chain.icon ? (
365
- <img src={chain.icon} alt={chain.name} className='ssw-chain-icon' />
366
- ) : (
367
- <div
368
- className='ssw-chain-icon-placeholder'
369
- style={{ backgroundColor: chain.color ?? '#888' }}
370
- >
371
- {chain.name.charAt(0)}
372
- </div>
373
- )}
374
- <span className='ssw-chain-name'>{chain.name}</span>
375
- </button>
376
- ))}
377
- </div>
378
- </div>
379
-
380
- <div className='ssw-token-panel'>
381
- <div className='ssw-search-wrapper'>
382
- <svg
383
- className='ssw-search-icon'
384
- width='16'
385
- height='16'
386
- viewBox='0 0 24 24'
387
- fill='none'
388
- stroke='currentColor'
389
- strokeWidth='2'
390
- >
391
- <circle cx='11' cy='11' r='8' />
392
- <path d='m21 21-4.35-4.35' />
393
- </svg>
394
- <input
395
- type='text'
396
- className='ssw-token-search'
397
- placeholder='Search for a token or paste address'
398
- value={searchQuery}
399
- onChange={e => setSearchQuery(e.target.value)}
400
- autoFocus
401
- />
402
- </div>
403
-
404
- <div className='ssw-token-list'>
405
- {isLoading ? (
406
- <div className='ssw-loading'>
407
- <div className='ssw-spinner' />
408
- <span>Loading assets...</span>
409
- </div>
410
- ) : sortedAssets.length === 0 ? (
411
- <div className='ssw-empty'>No tokens found</div>
412
- ) : (
413
- <Virtuoso
414
- data={sortedAssets}
415
- rangeChanged={setVisibleRange}
416
- overscan={200}
417
- itemContent={(_, asset) => {
418
- const chainInfo = chainInfoMap.get(asset.chainId)
419
- const balance = balances?.[asset.assetId]
420
- return (
421
- <button
422
- className='ssw-token-item'
423
- onClick={() => handleAssetSelect(asset)}
424
- type='button'
425
- >
426
- <div className='ssw-token-icon-wrapper'>
427
- {asset.icon ? (
428
- <img src={asset.icon} alt={asset.symbol} className='ssw-token-icon' />
429
- ) : (
430
- <div
431
- className='ssw-token-icon-placeholder'
432
- style={{ backgroundColor: asset.color ?? '#888' }}
433
- >
434
- {asset.symbol?.charAt(0) ?? '?'}
435
- </div>
436
- )}
437
- {chainInfo?.icon && (
438
- <img
439
- src={chainInfo.icon}
440
- alt={chainInfo.name}
441
- className='ssw-token-chain-badge'
442
- />
443
- )}
444
- </div>
445
- <div className='ssw-token-info'>
446
- <span className='ssw-token-symbol'>{asset.symbol}</span>
447
- <span className='ssw-token-name'>
448
- {chainInfo?.name ?? asset.networkName ?? asset.name}
449
- </span>
450
- </div>
451
- <div className='ssw-token-right'>
452
- {(walletAddress || bitcoinAddress || solanaAddress) &&
453
- (loadingAssetIds.has(asset.assetId) ? (
454
- <span className='ssw-token-balance-skeleton' />
455
- ) : balance && balance.balance !== '0' ? (
456
- <>
457
- {marketData?.[asset.assetId]?.price && (
458
- <span className='ssw-token-fiat-value'>
459
- $
460
- {bnOrZero(balance.balance)
461
- .div(bnOrZero(10).pow(asset.precision))
462
- .times(bnOrZero(marketData[asset.assetId].price))
463
- .toNumber()
464
- .toLocaleString(undefined, {
465
- minimumFractionDigits: 2,
466
- maximumFractionDigits: 2,
467
- })}
468
- </span>
469
- )}
470
- <span className='ssw-token-balance'>
471
- {balance.balanceFormatted}
472
- </span>
473
- </>
474
- ) : null)}
475
- </div>
476
- </button>
477
- )
478
- }}
479
- />
480
- )}
481
- </div>
482
- </div>
483
- </div>
484
- </div>
485
- </div>
486
- )
487
- }
@@ -1,92 +0,0 @@
1
- import { useAppKit, useAppKitAccount } from '@reown/appkit/react'
2
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
3
- import type { ReactNode } from 'react'
4
- import { useCallback, useEffect, useMemo, useState } from 'react'
5
- import type { WalletClient } from 'viem'
6
- import type { Config } from 'wagmi'
7
- import { useWalletClient, WagmiProvider } from 'wagmi'
8
-
9
- import { getWagmiAdapter, initializeAppKit } from '../config/appkit'
10
- import { useSwapWallet } from '../contexts/SwapWalletContext'
11
- import { truncateAddress } from '../types'
12
-
13
- const queryClient = new QueryClient()
14
-
15
- type InternalWalletProviderProps = {
16
- projectId: string
17
- children: (walletClient: WalletClient | undefined) => ReactNode
18
- }
19
-
20
- const InternalWalletContent = ({
21
- children,
22
- }: {
23
- children: (walletClient: WalletClient | undefined) => ReactNode
24
- }) => {
25
- const { data: walletClient } = useWalletClient()
26
- return <>{children(walletClient)}</>
27
- }
28
-
29
- export const InternalWalletProvider = ({ projectId, children }: InternalWalletProviderProps) => {
30
- const [isInitialized, setIsInitialized] = useState(false)
31
-
32
- useEffect(() => {
33
- initializeAppKit(projectId)
34
- setIsInitialized(true)
35
- }, [projectId])
36
-
37
- const wagmiConfig = useMemo((): Config | undefined => {
38
- if (!isInitialized) return undefined
39
- const adapter = getWagmiAdapter()
40
- return adapter?.wagmiConfig
41
- }, [isInitialized])
42
-
43
- if (!wagmiConfig) {
44
- return null
45
- }
46
-
47
- return (
48
- <WagmiProvider config={wagmiConfig}>
49
- <QueryClientProvider client={queryClient}>
50
- <InternalWalletContent>{children}</InternalWalletContent>
51
- </QueryClientProvider>
52
- </WagmiProvider>
53
- )
54
- }
55
-
56
- export const ConnectWalletButton = () => {
57
- const { open } = useAppKit()
58
- const { address: appKitAddress, isConnected: appKitConnected } = useAppKitAccount()
59
- const { walletAddress } = useSwapWallet()
60
-
61
- const connectedAddress = walletAddress ?? appKitAddress
62
- const isConnected = !!walletAddress || appKitConnected
63
-
64
- const handleClick = useCallback(() => {
65
- open()
66
- }, [open])
67
-
68
- if (!isConnected) {
69
- return (
70
- <button onClick={handleClick} type='button' className='ssw-connect-btn'>
71
- <svg
72
- width='16'
73
- height='16'
74
- viewBox='0 0 24 24'
75
- fill='none'
76
- stroke='currentColor'
77
- strokeWidth='2'
78
- >
79
- <path d='M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1' />
80
- <path d='M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4' />
81
- </svg>
82
- Connect
83
- </button>
84
- )
85
- }
86
-
87
- return (
88
- <button onClick={handleClick} type='button' className='ssw-connect-btn ssw-connected'>
89
- {connectedAddress ? truncateAddress(connectedAddress) : 'Connected'}
90
- </button>
91
- )
92
- }
@@ -1,104 +0,0 @@
1
- import {
2
- arbitrum,
3
- avalanche,
4
- base,
5
- bitcoin,
6
- bsc,
7
- gnosis,
8
- hyperEvm,
9
- katana,
10
- mainnet,
11
- monad,
12
- optimism,
13
- plasma,
14
- polygon,
15
- solana,
16
- worldchain,
17
- } from '@reown/appkit/networks'
18
- import { createAppKit } from '@reown/appkit/react'
19
- import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin'
20
- import { SolanaAdapter } from '@reown/appkit-adapter-solana/react'
21
- import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'
22
- import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'
23
-
24
- export const EVM_NETWORKS = [
25
- mainnet,
26
- polygon,
27
- arbitrum,
28
- optimism,
29
- base,
30
- avalanche,
31
- bsc,
32
- gnosis,
33
- monad,
34
- hyperEvm,
35
- plasma,
36
- worldchain,
37
- katana,
38
- ] as const
39
-
40
- export const ALL_NETWORKS = [...EVM_NETWORKS, bitcoin, solana] as const
41
-
42
- export type SupportedNetwork = (typeof ALL_NETWORKS)[number]
43
- export type EvmNetwork = (typeof EVM_NETWORKS)[number]
44
-
45
- const APP_METADATA = {
46
- name: 'ShapeShift Swap Widget',
47
- description: 'Multi-chain swap widget powered by ShapeShift',
48
- url: 'https://shapeshift.com',
49
- icons: ['https://shapeshift.com/icon.png'],
50
- }
51
-
52
- let wagmiAdapter: WagmiAdapter | null = null
53
- let bitcoinAdapter: BitcoinAdapter | null = null
54
- let solanaAdapter: SolanaAdapter | null = null
55
- let appKitInitialized = false
56
-
57
- export const createWagmiAdapter = (projectId: string): WagmiAdapter => {
58
- if (!wagmiAdapter) {
59
- wagmiAdapter = new WagmiAdapter({
60
- networks: [...EVM_NETWORKS],
61
- projectId,
62
- })
63
- }
64
- return wagmiAdapter
65
- }
66
-
67
- export const createBitcoinAdapter = (): BitcoinAdapter => {
68
- if (!bitcoinAdapter) {
69
- bitcoinAdapter = new BitcoinAdapter()
70
- }
71
- return bitcoinAdapter
72
- }
73
-
74
- export const createSolanaAdapter = (): SolanaAdapter => {
75
- if (!solanaAdapter) {
76
- solanaAdapter = new SolanaAdapter({
77
- wallets: [new PhantomWalletAdapter(), new SolflareWalletAdapter()] as any,
78
- })
79
- }
80
- return solanaAdapter
81
- }
82
-
83
- export const getWagmiAdapter = (): WagmiAdapter | null => wagmiAdapter
84
-
85
- export const initializeAppKit = (projectId: string): void => {
86
- if (appKitInitialized) {
87
- return
88
- }
89
-
90
- const wagmi = createWagmiAdapter(projectId)
91
- const btc = createBitcoinAdapter()
92
- const sol = createSolanaAdapter()
93
-
94
- createAppKit({
95
- adapters: [wagmi, btc, sol],
96
- projectId,
97
- networks: [...ALL_NETWORKS],
98
- metadata: APP_METADATA,
99
- })
100
-
101
- appKitInitialized = true
102
- }
103
-
104
- export const isAppKitInitialized = (): boolean => appKitInitialized
@@ -1,27 +0,0 @@
1
- import {
2
- arbitrum,
3
- avalanche,
4
- base,
5
- bsc,
6
- gnosis,
7
- mainnet,
8
- optimism,
9
- polygon,
10
- } from '@reown/appkit/networks'
11
- import type { Config } from 'wagmi'
12
-
13
- export const SUPPORTED_CHAINS = [
14
- mainnet,
15
- polygon,
16
- arbitrum,
17
- optimism,
18
- base,
19
- avalanche,
20
- bsc,
21
- gnosis,
22
- ] as const
23
-
24
- export type SupportedChains = typeof SUPPORTED_CHAINS
25
- export type SupportedChainId = SupportedChains[number]['id']
26
-
27
- export type WagmiConfig = Config