@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.
Files changed (158) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +18 -11
  3. package/package.json +77 -28
  4. package/Dockerfile +0 -87
  5. package/dist/assets/PhArrowCircleDown-B305t-Sh.js +0 -14
  6. package/dist/assets/PhArrowClockwise-CJPxQhr_.js +0 -14
  7. package/dist/assets/PhArrowDown-C4hT9BVu.js +0 -14
  8. package/dist/assets/PhArrowLeft-Way4Cu-r.js +0 -14
  9. package/dist/assets/PhArrowRight-Cp5ZME0F.js +0 -14
  10. package/dist/assets/PhArrowSquareOut-NnrK69c5.js +0 -14
  11. package/dist/assets/PhArrowUp-Dph6j8rm.js +0 -14
  12. package/dist/assets/PhArrowUpRight-BpJjRRRh.js +0 -14
  13. package/dist/assets/PhArrowsClockwise-CFUT8X7R.js +0 -14
  14. package/dist/assets/PhArrowsDownUp-BjBI4ckC.js +0 -14
  15. package/dist/assets/PhArrowsLeftRight-CuLpbKRk.js +0 -14
  16. package/dist/assets/PhBank-Dchr4XQJ.js +0 -14
  17. package/dist/assets/PhBrowser-dUu2TrC1.js +0 -14
  18. package/dist/assets/PhCaretDown-78IuKU3V.js +0 -14
  19. package/dist/assets/PhCaretLeft-_aiyH7n1.js +0 -14
  20. package/dist/assets/PhCaretRight-8zJQEuDX.js +0 -14
  21. package/dist/assets/PhCaretUp-CiCxKWwN.js +0 -14
  22. package/dist/assets/PhCheck-CcADx8br.js +0 -14
  23. package/dist/assets/PhCircleHalf-BYzSzd2h.js +0 -14
  24. package/dist/assets/PhClock-UItiXeJq.js +0 -14
  25. package/dist/assets/PhCompass-CUy3uA7t.js +0 -14
  26. package/dist/assets/PhCopy-C-PDgSlZ.js +0 -14
  27. package/dist/assets/PhCreditCard-CWRaUT6F.js +0 -14
  28. package/dist/assets/PhCurrencyDollar-Cqla3AXT.js +0 -14
  29. package/dist/assets/PhDesktop-BBIPrYLl.js +0 -14
  30. package/dist/assets/PhDeviceMobile-BdsPaATg.js +0 -14
  31. package/dist/assets/PhDotsThree-BMXCQl-0.js +0 -14
  32. package/dist/assets/PhEnvelope-yUsis6yU.js +0 -14
  33. package/dist/assets/PhFunnelSimple-Ba7BbWTp.js +0 -14
  34. package/dist/assets/PhGlobe-DgLxBk5U.js +0 -14
  35. package/dist/assets/PhIdentificationCard-Czjmq9Z3.js +0 -14
  36. package/dist/assets/PhImage-BAJ_erz6.js +0 -14
  37. package/dist/assets/PhInfo-Cr4DhVUE.js +0 -14
  38. package/dist/assets/PhLightbulb-BX_7duTr.js +0 -14
  39. package/dist/assets/PhMagnifyingGlass-Mygfryvz.js +0 -14
  40. package/dist/assets/PhPaperPlaneRight-BeuCA660.js +0 -14
  41. package/dist/assets/PhPlus-BMjcHjsT.js +0 -14
  42. package/dist/assets/PhPower-CGffGmdb.js +0 -14
  43. package/dist/assets/PhPuzzlePiece-wm_GpVSi.js +0 -14
  44. package/dist/assets/PhQrCode-DRwRzXCH.js +0 -14
  45. package/dist/assets/PhQuestion-M09j2U0T.js +0 -14
  46. package/dist/assets/PhQuestionMark-BP9EMB6h.js +0 -14
  47. package/dist/assets/PhSealCheck-BfG80yKn.js +0 -14
  48. package/dist/assets/PhSignOut-C5YOWlPT.js +0 -14
  49. package/dist/assets/PhSpinner-BXooDYzU.js +0 -14
  50. package/dist/assets/PhTrash-Biq6rmmL.js +0 -14
  51. package/dist/assets/PhUser-CAgZSpGe.js +0 -14
  52. package/dist/assets/PhVault-l2PHF38a.js +0 -14
  53. package/dist/assets/PhWallet-w25D16It.js +0 -14
  54. package/dist/assets/PhWarning-DPEydIPw.js +0 -14
  55. package/dist/assets/PhWarningCircle-BqjT745H.js +0 -14
  56. package/dist/assets/PhX-s-SmVExa.js +0 -14
  57. package/dist/assets/SwapController-If0bFrNc.js +0 -1
  58. package/dist/assets/ccip-BBB7uCdL.js +0 -1
  59. package/dist/assets/ccip-CkkdfKKI.js +0 -1
  60. package/dist/assets/data-capture-D4gAy-Yc.js +0 -242
  61. package/dist/assets/email-B1AJehis.js +0 -90
  62. package/dist/assets/embedded-wallet-Q6DQopDk.js +0 -410
  63. package/dist/assets/features-B6JAPAFb.js +0 -5
  64. package/dist/assets/index-5jd8RPN9.js +0 -7428
  65. package/dist/assets/index-B4kNtSTk.js +0 -1080
  66. package/dist/assets/index-B753eAob.js +0 -1
  67. package/dist/assets/index-BZoLTv77.js +0 -3
  68. package/dist/assets/index-Bcw9UURX.js +0 -3
  69. package/dist/assets/index-BkrV-ahK.js +0 -2
  70. package/dist/assets/index-CRQzQ_up.js +0 -9
  71. package/dist/assets/index-CSW0Gt5y.js +0 -132
  72. package/dist/assets/index-CZ4jTIsk.js +0 -138
  73. package/dist/assets/index-Cwa8SB3h.js +0 -61
  74. package/dist/assets/index-DEwQgT4r.js +0 -78
  75. package/dist/assets/index-DVfQiQ1d.js +0 -1
  76. package/dist/assets/index-cV3UdaMs.css +0 -1
  77. package/dist/assets/index-hAmu622O.js +0 -43
  78. package/dist/assets/onramp-XcPNCLRU.js +0 -422
  79. package/dist/assets/pay-with-exchange-BeHt4OF4.js +0 -280
  80. package/dist/assets/property-C9JG5tag.js +0 -27
  81. package/dist/assets/receive-7ff4he2S.js +0 -131
  82. package/dist/assets/send-CkMBIRXT.js +0 -554
  83. package/dist/assets/socials-DmmxuLrP.js +0 -250
  84. package/dist/assets/swaps-IHAYRQ0x.js +0 -1050
  85. package/dist/assets/transactions-9Cxdk7o9.js +0 -16
  86. package/dist/assets/v4-BOvFkHkt.js +0 -1
  87. package/dist/assets/w3m-modal-kJzFnBfB.js +0 -891
  88. package/dist/assets/wallet-standard-Dv8LMoUB.js +0 -1
  89. package/dist/favicon.png +0 -0
  90. package/dist/favicon.svg +0 -11
  91. package/dist/icon-192x192.png +0 -0
  92. package/dist/icon-512x512.png +0 -0
  93. package/dist/index.html +0 -33
  94. package/index.html +0 -32
  95. package/public/favicon.png +0 -0
  96. package/public/favicon.svg +0 -11
  97. package/public/icon-192x192.png +0 -0
  98. package/public/icon-512x512.png +0 -0
  99. package/railway.toml +0 -10
  100. package/src/api/client.ts +0 -95
  101. package/src/components/AddressInputModal.css +0 -173
  102. package/src/components/AddressInputModal.tsx +0 -250
  103. package/src/components/ApprovalStep.tsx +0 -92
  104. package/src/components/ExecutionStep.tsx +0 -27
  105. package/src/components/InputStep.tsx +0 -431
  106. package/src/components/QuoteSelector.css +0 -146
  107. package/src/components/QuoteSelector.tsx +0 -137
  108. package/src/components/QuotesModal.css +0 -250
  109. package/src/components/QuotesModal.tsx +0 -182
  110. package/src/components/SettingsModal.css +0 -145
  111. package/src/components/SettingsModal.tsx +0 -180
  112. package/src/components/StatusStep.tsx +0 -139
  113. package/src/components/SwapWidget.css +0 -713
  114. package/src/components/SwapWidget.tsx +0 -607
  115. package/src/components/TokenSelectModal.css +0 -438
  116. package/src/components/TokenSelectModal.tsx +0 -487
  117. package/src/components/WalletProvider.tsx +0 -92
  118. package/src/config/appkit.ts +0 -104
  119. package/src/config/wagmi.ts +0 -27
  120. package/src/constants/chains.ts +0 -72
  121. package/src/constants/defaults.ts +0 -28
  122. package/src/constants/swappers.ts +0 -48
  123. package/src/constants/viemChains.ts +0 -69
  124. package/src/contexts/SwapWalletContext.tsx +0 -25
  125. package/src/demo/App.css +0 -458
  126. package/src/demo/App.tsx +0 -481
  127. package/src/demo/main.tsx +0 -25
  128. package/src/hooks/useAssets.ts +0 -180
  129. package/src/hooks/useBalances.ts +0 -822
  130. package/src/hooks/useBitcoinSigning.ts +0 -276
  131. package/src/hooks/useMarketData.ts +0 -169
  132. package/src/hooks/useSolanaSigning.ts +0 -275
  133. package/src/hooks/useStatusPolling.ts +0 -137
  134. package/src/hooks/useSwapApproval.ts +0 -106
  135. package/src/hooks/useSwapDisplayValues.ts +0 -157
  136. package/src/hooks/useSwapExecution.ts +0 -199
  137. package/src/hooks/useSwapHandlers.ts +0 -119
  138. package/src/hooks/useSwapQuote.ts +0 -71
  139. package/src/hooks/useSwapQuoting.ts +0 -102
  140. package/src/hooks/useSwapRates.ts +0 -61
  141. package/src/index.ts +0 -43
  142. package/src/machines/SwapMachineContext.ts +0 -5
  143. package/src/machines/__tests__/guards.test.ts +0 -228
  144. package/src/machines/__tests__/setup.test.ts +0 -7
  145. package/src/machines/__tests__/swapMachine.test.ts +0 -544
  146. package/src/machines/__tests__/types.test.ts +0 -124
  147. package/src/machines/guards.ts +0 -33
  148. package/src/machines/swapMachine.ts +0 -288
  149. package/src/machines/types.ts +0 -54
  150. package/src/services/transactionStatus.ts +0 -322
  151. package/src/types/index.ts +0 -361
  152. package/src/utils/addressValidation.ts +0 -201
  153. package/src/utils/redirect.ts +0 -45
  154. package/src/vite-env.d.ts +0 -10
  155. package/tsconfig.json +0 -23
  156. package/tsconfig.node.json +0 -10
  157. package/vite.config.ts +0 -101
  158. package/vitest.config.ts +0 -18
@@ -1,276 +0,0 @@
1
- import { useAppKitAccount, useAppKitProvider } from '@reown/appkit/react'
2
- import type { BitcoinConnector } from '@reown/appkit-adapter-bitcoin'
3
- import { useCallback, useMemo, useState } from 'react'
4
-
5
- import { checkBitcoinStatus } from '../services/transactionStatus'
6
-
7
- type AccountAddress = string | { address?: string; purpose?: string | number }
8
-
9
- type AccountAddressArray = AccountAddress[]
10
-
11
- export type SignInput = {
12
- address: string
13
- index: number
14
- sighashTypes?: number[]
15
- }
16
-
17
- type BitcoinConnectorExtended = BitcoinConnector & {
18
- getAccountAddresses?: () => Promise<AccountAddressArray> | AccountAddressArray
19
- signPSBT?: (params: {
20
- psbt: string
21
- signInputs: SignInput[]
22
- broadcast?: boolean
23
- }) => Promise<string | { txid?: string; psbt?: string }>
24
- signMessage?: (params: {
25
- message: string
26
- address: string
27
- }) => Promise<string | { signature?: string }>
28
- }
29
-
30
- export type SendTransferParams = {
31
- recipientAddress: string
32
- amount: string
33
- memo?: string
34
- }
35
-
36
- export type SignPsbtParams = {
37
- psbt: string
38
- signInputs: SignInput[]
39
- broadcast?: boolean
40
- }
41
-
42
- export type BitcoinSigningState = {
43
- isLoading: boolean
44
- error: string | undefined
45
- txid: string | undefined
46
- }
47
-
48
- export type UseBitcoinSigningResult = {
49
- isConnected: boolean
50
- address: string | undefined
51
- sendTransfer: (params: SendTransferParams) => Promise<string>
52
- signPsbt: (params: SignPsbtParams) => Promise<string>
53
- signMessage: (message: string) => Promise<string>
54
- getAccountAddresses: () => Promise<string[]>
55
- state: BitcoinSigningState
56
- reset: () => void
57
- checkTxStatus: (
58
- txid: string,
59
- network?: 'mainnet' | 'testnet',
60
- ) => ReturnType<typeof checkBitcoinStatus>
61
- }
62
-
63
- export const useBitcoinSigning = (): UseBitcoinSigningResult => {
64
- const { walletProvider } = useAppKitProvider<BitcoinConnector>('bip122')
65
- const provider = walletProvider as BitcoinConnectorExtended | undefined
66
-
67
- const [state, setState] = useState<BitcoinSigningState>({
68
- isLoading: false,
69
- error: undefined,
70
- txid: undefined,
71
- })
72
-
73
- const {
74
- address: appKitBtcAddress,
75
- allAccounts: btcAccounts,
76
- isConnected: isBtcConnected,
77
- } = useAppKitAccount({ namespace: 'bip122' })
78
-
79
- const address = useMemo(() => {
80
- if (!provider || !isBtcConnected) return undefined
81
- return appKitBtcAddress ?? btcAccounts[0]?.address
82
- }, [provider, isBtcConnected, appKitBtcAddress, btcAccounts])
83
-
84
- const sendTransfer = useCallback(
85
- async (params: SendTransferParams): Promise<string> => {
86
- if (!provider?.sendTransfer) {
87
- throw new Error('Bitcoin wallet not connected')
88
- }
89
-
90
- setState(prev => ({ ...prev, isLoading: true, error: undefined, txid: undefined }))
91
-
92
- try {
93
- const txid = await provider.sendTransfer({
94
- recipient: params.recipientAddress,
95
- amount: params.amount,
96
- ...(params.memo && { memo: params.memo }),
97
- })
98
-
99
- if (!txid) {
100
- throw new Error('Transaction submitted but no txid returned')
101
- }
102
-
103
- setState(prev => ({ ...prev, isLoading: false, txid }))
104
- return txid
105
- } catch (error) {
106
- const errorMessage =
107
- error instanceof Error ? error.message : 'Failed to send Bitcoin transfer'
108
-
109
- if (
110
- errorMessage.toLowerCase().includes('rejected') ||
111
- errorMessage.toLowerCase().includes('denied') ||
112
- errorMessage.toLowerCase().includes('cancelled') ||
113
- errorMessage.toLowerCase().includes('user refused')
114
- ) {
115
- setState(prev => ({ ...prev, isLoading: false, error: 'Transaction rejected by user' }))
116
- throw new Error('Transaction rejected by user')
117
- }
118
-
119
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
120
- throw error
121
- }
122
- },
123
- [provider],
124
- )
125
-
126
- const signPsbt = useCallback(
127
- async (params: SignPsbtParams): Promise<string> => {
128
- if (!provider?.signPSBT) {
129
- throw new Error('Bitcoin wallet not connected')
130
- }
131
-
132
- setState(prev => ({ ...prev, isLoading: true, error: undefined, txid: undefined }))
133
-
134
- try {
135
- const result = await provider.signPSBT({
136
- psbt: params.psbt,
137
- signInputs: params.signInputs,
138
- broadcast: params.broadcast ?? true,
139
- })
140
-
141
- const txidOrPsbt = typeof result === 'string' ? result : result?.txid ?? result?.psbt ?? ''
142
-
143
- if (params.broadcast !== false) {
144
- setState(prev => ({ ...prev, isLoading: false, txid: txidOrPsbt }))
145
- } else {
146
- setState(prev => ({ ...prev, isLoading: false }))
147
- }
148
-
149
- return txidOrPsbt
150
- } catch (error) {
151
- const errorMessage = error instanceof Error ? error.message : 'Failed to sign PSBT'
152
-
153
- if (
154
- errorMessage.toLowerCase().includes('rejected') ||
155
- errorMessage.toLowerCase().includes('denied') ||
156
- errorMessage.toLowerCase().includes('cancelled') ||
157
- errorMessage.toLowerCase().includes('user refused')
158
- ) {
159
- setState(prev => ({ ...prev, isLoading: false, error: 'Signing rejected by user' }))
160
- throw new Error('Signing rejected by user')
161
- }
162
-
163
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
164
- throw error
165
- }
166
- },
167
- [provider],
168
- )
169
-
170
- const signMessage = useCallback(
171
- async (message: string): Promise<string> => {
172
- if (!provider?.signMessage) {
173
- throw new Error('Bitcoin wallet not connected')
174
- }
175
-
176
- if (!address) {
177
- const errorMessage = 'No Bitcoin address available to sign with'
178
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
179
- throw new Error(errorMessage)
180
- }
181
-
182
- setState(prev => ({ ...prev, isLoading: true, error: undefined }))
183
-
184
- try {
185
- const signature = await provider.signMessage({
186
- message,
187
- address,
188
- })
189
-
190
- const signatureObj = signature as string | { signature?: string }
191
- const signatureStr =
192
- typeof signatureObj === 'string'
193
- ? signatureObj
194
- : (signatureObj && typeof signatureObj === 'object' && 'signature' in signatureObj
195
- ? signatureObj.signature
196
- : '') ?? ''
197
-
198
- if (!signatureStr) {
199
- throw new Error('Signing succeeded but no signature returned')
200
- }
201
-
202
- setState(prev => ({ ...prev, isLoading: false }))
203
- return signatureStr
204
- } catch (error) {
205
- const errorMessage = error instanceof Error ? error.message : 'Failed to sign message'
206
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
207
- throw error
208
- }
209
- },
210
- [provider, address],
211
- )
212
-
213
- const getAccountAddresses = useCallback(async (): Promise<string[]> => {
214
- if (!provider) {
215
- return []
216
- }
217
-
218
- try {
219
- const accountsResult = provider.getAccountAddresses?.()
220
- const accounts: AccountAddressArray | undefined =
221
- accountsResult instanceof Promise
222
- ? await accountsResult
223
- : (accountsResult as AccountAddressArray | undefined)
224
-
225
- if (!accounts || !Array.isArray(accounts)) return []
226
-
227
- return accounts
228
- .map((account: AccountAddress) => {
229
- if (typeof account === 'string') return account
230
- return account?.address ?? ''
231
- })
232
- .filter((addr: string | undefined): addr is string => Boolean(addr))
233
- } catch {
234
- return []
235
- }
236
- }, [provider])
237
-
238
- const reset = useCallback(() => {
239
- setState({
240
- isLoading: false,
241
- error: undefined,
242
- txid: undefined,
243
- })
244
- }, [])
245
-
246
- const checkTxStatus = useCallback((txid: string, network: 'mainnet' | 'testnet' = 'mainnet') => {
247
- return checkBitcoinStatus(txid, network)
248
- }, [])
249
-
250
- const isConnected = !!provider && !!address
251
-
252
- return useMemo(
253
- () => ({
254
- isConnected,
255
- address,
256
- sendTransfer,
257
- signPsbt,
258
- signMessage,
259
- getAccountAddresses,
260
- state,
261
- reset,
262
- checkTxStatus,
263
- }),
264
- [
265
- isConnected,
266
- address,
267
- sendTransfer,
268
- signPsbt,
269
- signMessage,
270
- getAccountAddresses,
271
- state,
272
- reset,
273
- checkTxStatus,
274
- ],
275
- )
276
- }
@@ -1,169 +0,0 @@
1
- import { adapters } from '@shapeshiftoss/caip'
2
- import { BigAmount, bn } from '@shapeshiftoss/utils'
3
- import { useQuery } from '@tanstack/react-query'
4
-
5
- import type { AssetId } from '../types'
6
-
7
- const MARKET_DATA_STALE_TIME = 10 * 60 * 1000
8
- const MARKET_DATA_GC_TIME = 60 * 60 * 1000
9
-
10
- type MarketData = {
11
- price: string
12
- marketCap: string
13
- volume: string
14
- changePercent24Hr: number
15
- }
16
-
17
- export type MarketDataById = Record<AssetId, MarketData>
18
-
19
- type CoinGeckoMarketCap = {
20
- id: string
21
- symbol: string
22
- current_price: number
23
- market_cap: number
24
- total_volume: number
25
- price_change_percentage_24h: number
26
- }
27
-
28
- const COINGECKO_PROXY_URL = 'https://api.proxy.shapeshift.com/api/v1/markets'
29
- const COINGECKO_DIRECT_URL = 'https://api.coingecko.com/api/v3'
30
-
31
- const fetchWithRetry = async (url: string, retries = 2, delay = 1000): Promise<Response> => {
32
- for (let i = 0; i <= retries; i++) {
33
- try {
34
- const response = await fetch(url)
35
- if (response.ok) return response
36
- if (response.status === 429 && i < retries) {
37
- await new Promise(r => setTimeout(r, delay * (i + 1)))
38
- continue
39
- }
40
- return response
41
- } catch (error) {
42
- if (i === retries) throw error
43
- await new Promise(r => setTimeout(r, delay * (i + 1)))
44
- }
45
- }
46
- throw new Error('Failed after retries')
47
- }
48
-
49
- const fetchMarketsPage = async (
50
- baseUrl: string,
51
- page: number,
52
- perPage: number,
53
- ): Promise<CoinGeckoMarketCap[]> => {
54
- const url = `${baseUrl}/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=${perPage}&page=${page}&sparkline=false`
55
- const response = await fetchWithRetry(url)
56
- if (!response.ok) return []
57
- return response.json()
58
- }
59
-
60
- const fetchAllMarketData = async (): Promise<MarketDataById> => {
61
- const result: MarketDataById = {}
62
- const perPage = 250
63
- const totalPages = 2
64
-
65
- let baseUrl = COINGECKO_PROXY_URL
66
-
67
- const controller = new AbortController()
68
- const timeoutId = setTimeout(() => controller.abort(), 5000)
69
-
70
- const testResponse = await fetch(
71
- `${COINGECKO_PROXY_URL}/coins/markets?vs_currency=usd&per_page=1&page=1`,
72
- { signal: controller.signal },
73
- ).catch(() => null)
74
-
75
- clearTimeout(timeoutId)
76
-
77
- if (!testResponse?.ok) {
78
- baseUrl = COINGECKO_DIRECT_URL
79
- }
80
-
81
- try {
82
- const allData: CoinGeckoMarketCap[] = []
83
-
84
- for (let page = 1; page <= totalPages; page++) {
85
- const pageData = await fetchMarketsPage(baseUrl, page, perPage)
86
- allData.push(...pageData)
87
-
88
- if (page < totalPages) {
89
- await new Promise(r => setTimeout(r, 500))
90
- }
91
- }
92
-
93
- for (const asset of allData) {
94
- const assetIds = adapters.coingeckoToAssetIds(asset.id)
95
- if (!assetIds?.length) continue
96
-
97
- const marketData: MarketData = {
98
- price: asset.current_price?.toString() ?? '0',
99
- marketCap: asset.market_cap?.toString() ?? '0',
100
- volume: asset.total_volume?.toString() ?? '0',
101
- changePercent24Hr: asset.price_change_percentage_24h ?? 0,
102
- }
103
-
104
- for (const assetId of assetIds) {
105
- result[assetId] = marketData
106
- }
107
- }
108
- } catch (error) {
109
- console.error('Failed to fetch market data:', error)
110
- }
111
-
112
- return result
113
- }
114
-
115
- export const useAllMarketData = () => {
116
- return useQuery({
117
- queryKey: ['allMarketData'],
118
- queryFn: fetchAllMarketData,
119
- staleTime: MARKET_DATA_STALE_TIME,
120
- gcTime: MARKET_DATA_GC_TIME,
121
- retry: 1,
122
- retryDelay: 5000,
123
- })
124
- }
125
-
126
- export const useMarketData = (assetIds: AssetId[]) => {
127
- const { data: allMarketData, ...rest } = useAllMarketData()
128
-
129
- const filteredData = (() => {
130
- if (!allMarketData) return {}
131
-
132
- const result: MarketDataById = {}
133
- for (const assetId of assetIds) {
134
- if (allMarketData[assetId]) {
135
- result[assetId] = allMarketData[assetId]
136
- }
137
- }
138
- return result
139
- })()
140
-
141
- return { data: filteredData, ...rest }
142
- }
143
-
144
- export const useAssetPrice = (assetId: AssetId | undefined) => {
145
- const { data: allMarketData, ...rest } = useAllMarketData()
146
-
147
- return {
148
- data: assetId ? allMarketData?.[assetId]?.price : undefined,
149
- ...rest,
150
- }
151
- }
152
-
153
- export const formatUsdValue = (
154
- cryptoAmount: string,
155
- precision: number,
156
- usdPrice: string | undefined,
157
- ): string => {
158
- if (!usdPrice || usdPrice === '0') return '$0.00'
159
-
160
- const amount = BigAmount.fromBaseUnit({ value: cryptoAmount, precision }).toPrecision()
161
- const usdValue = bn(amount).times(usdPrice).toNumber()
162
-
163
- if (usdValue < 0.01) return '< $0.01'
164
- if (usdValue < 1000) return `$${usdValue.toFixed(2)}`
165
- if (usdValue < 1000000) return `$${(usdValue / 1000).toFixed(2)}K`
166
- return `$${(usdValue / 1000000).toFixed(2)}M`
167
- }
168
-
169
- export type { MarketData }
@@ -1,275 +0,0 @@
1
- import { useAppKitProvider } from '@reown/appkit/react'
2
- import type { Provider } from '@reown/appkit-adapter-solana/react'
3
- import { useAppKitConnection } from '@reown/appkit-adapter-solana/react'
4
- import type { Transaction, VersionedTransaction } from '@solana/web3.js'
5
- import { useCallback, useMemo, useState } from 'react'
6
-
7
- import { checkSolanaStatus, waitForSolanaConfirmation } from '../services/transactionStatus'
8
-
9
- type AnyTransaction = Transaction | VersionedTransaction
10
- type TransactionSignature = string | { toString: () => string }
11
- type MessageSignature = Uint8Array
12
-
13
- type SolanaProviderExtended = Provider & {
14
- sendTransaction?: (
15
- transaction: AnyTransaction,
16
- connection: unknown,
17
- ) => Promise<TransactionSignature>
18
- signTransaction?: <T extends AnyTransaction>(transaction: T) => Promise<T>
19
- signMessage?: (message: Uint8Array) => Promise<MessageSignature>
20
- }
21
-
22
- export type SendTransactionParams = {
23
- transaction: Transaction | VersionedTransaction
24
- }
25
-
26
- export type SignMessageParams = {
27
- message: Uint8Array | string
28
- }
29
-
30
- export type SolanaSigningState = {
31
- isLoading: boolean
32
- error: string | undefined
33
- signature: string | undefined
34
- }
35
-
36
- export type UseSolanaSigningResult = {
37
- isConnected: boolean
38
- address: string | undefined
39
- connection: ReturnType<typeof useAppKitConnection>['connection']
40
- sendTransaction: (params: SendTransactionParams) => Promise<string>
41
- signMessage: (params: SignMessageParams) => Promise<Uint8Array>
42
- signTransaction: <T extends Transaction | VersionedTransaction>(transaction: T) => Promise<T>
43
- state: SolanaSigningState
44
- reset: () => void
45
- checkTxStatus: (signature: string) => ReturnType<typeof checkSolanaStatus>
46
- waitForConfirmation: (
47
- signature: string,
48
- commitment?: 'confirmed' | 'finalized',
49
- ) => ReturnType<typeof waitForSolanaConfirmation>
50
- }
51
-
52
- export const useSolanaSigning = (): UseSolanaSigningResult => {
53
- const { walletProvider } = useAppKitProvider<Provider>('solana')
54
- const provider = walletProvider as SolanaProviderExtended | undefined
55
- const { connection } = useAppKitConnection()
56
-
57
- const [state, setState] = useState<SolanaSigningState>({
58
- isLoading: false,
59
- error: undefined,
60
- signature: undefined,
61
- })
62
-
63
- const address = useMemo(() => {
64
- if (!provider) {
65
- return undefined
66
- }
67
-
68
- try {
69
- const publicKey = provider.publicKey
70
- if (!publicKey) {
71
- return undefined
72
- }
73
-
74
- const addressStr = publicKey?.toBase58?.() ?? publicKey?.toString?.() ?? undefined
75
- return addressStr
76
- } catch {
77
- return undefined
78
- }
79
- }, [provider])
80
-
81
- const sendTransaction = useCallback(
82
- async (params: SendTransactionParams): Promise<string> => {
83
- if (!provider?.sendTransaction) {
84
- throw new Error('Solana wallet not connected')
85
- }
86
-
87
- if (!connection) {
88
- throw new Error('Solana connection not available')
89
- }
90
-
91
- setState(prev => ({ ...prev, isLoading: true, error: undefined, signature: undefined }))
92
-
93
- try {
94
- const signature: TransactionSignature = await provider.sendTransaction(
95
- params.transaction,
96
- connection,
97
- )
98
-
99
- const signatureStr = typeof signature === 'string' ? signature : signature.toString()
100
-
101
- if (!signatureStr) {
102
- throw new Error('Transaction submitted but no signature returned')
103
- }
104
-
105
- setState(prev => ({ ...prev, isLoading: false, signature: signatureStr }))
106
- return signatureStr
107
- } catch (error) {
108
- const errorMessage =
109
- error instanceof Error ? error.message : 'Failed to send Solana transaction'
110
-
111
- if (
112
- errorMessage.toLowerCase().includes('rejected') ||
113
- errorMessage.toLowerCase().includes('denied') ||
114
- errorMessage.toLowerCase().includes('cancelled') ||
115
- errorMessage.toLowerCase().includes('user refused') ||
116
- errorMessage.toLowerCase().includes('user rejected')
117
- ) {
118
- setState(prev => ({ ...prev, isLoading: false, error: 'Transaction rejected by user' }))
119
- throw new Error('Transaction rejected by user')
120
- }
121
-
122
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
123
- throw error
124
- }
125
- },
126
- [provider, connection],
127
- )
128
-
129
- const signTransaction = useCallback(
130
- async <T extends Transaction | VersionedTransaction>(transaction: T): Promise<T> => {
131
- if (!provider?.signTransaction) {
132
- throw new Error('Solana wallet not connected or does not support signTransaction')
133
- }
134
-
135
- setState(prev => ({ ...prev, isLoading: true, error: undefined }))
136
-
137
- try {
138
- const signedTransaction = await provider.signTransaction(transaction)
139
-
140
- setState(prev => ({ ...prev, isLoading: false }))
141
- return signedTransaction as T
142
- } catch (error) {
143
- const errorMessage = error instanceof Error ? error.message : 'Failed to sign transaction'
144
-
145
- if (
146
- errorMessage.toLowerCase().includes('rejected') ||
147
- errorMessage.toLowerCase().includes('denied') ||
148
- errorMessage.toLowerCase().includes('cancelled') ||
149
- errorMessage.toLowerCase().includes('user refused') ||
150
- errorMessage.toLowerCase().includes('user rejected')
151
- ) {
152
- setState(prev => ({ ...prev, isLoading: false, error: 'Signing rejected by user' }))
153
- throw new Error('Signing rejected by user')
154
- }
155
-
156
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
157
- throw error
158
- }
159
- },
160
- [provider],
161
- )
162
-
163
- const signMessage = useCallback(
164
- async (params: SignMessageParams): Promise<Uint8Array> => {
165
- if (!provider?.signMessage) {
166
- throw new Error('Solana wallet not connected or does not support signMessage')
167
- }
168
-
169
- setState(prev => ({ ...prev, isLoading: true, error: undefined }))
170
-
171
- try {
172
- const messageBytes =
173
- typeof params.message === 'string'
174
- ? new TextEncoder().encode(params.message)
175
- : params.message
176
-
177
- const signature = await provider.signMessage(messageBytes)
178
-
179
- setState(prev => ({ ...prev, isLoading: false }))
180
- return signature
181
- } catch (error) {
182
- const errorMessage = error instanceof Error ? error.message : 'Failed to sign message'
183
-
184
- if (
185
- errorMessage.toLowerCase().includes('rejected') ||
186
- errorMessage.toLowerCase().includes('denied') ||
187
- errorMessage.toLowerCase().includes('cancelled') ||
188
- errorMessage.toLowerCase().includes('user refused') ||
189
- errorMessage.toLowerCase().includes('user rejected')
190
- ) {
191
- setState(prev => ({
192
- ...prev,
193
- isLoading: false,
194
- error: 'Message signing rejected by user',
195
- }))
196
- throw new Error('Message signing rejected by user')
197
- }
198
-
199
- setState(prev => ({ ...prev, isLoading: false, error: errorMessage }))
200
- throw error
201
- }
202
- },
203
- [provider],
204
- )
205
-
206
- const reset = useCallback(() => {
207
- setState({
208
- isLoading: false,
209
- error: undefined,
210
- signature: undefined,
211
- })
212
- }, [])
213
-
214
- const checkTxStatus = useCallback(
215
- (signature: string) => {
216
- if (!connection) {
217
- return Promise.resolve({
218
- status: 'pending' as const,
219
- error: 'Solana connection not available',
220
- })
221
- }
222
- return checkSolanaStatus(
223
- signature,
224
- connection as unknown as Parameters<typeof checkSolanaStatus>[1],
225
- )
226
- },
227
- [connection],
228
- )
229
-
230
- const waitForConfirmation = useCallback(
231
- (signature: string, commitment: 'confirmed' | 'finalized' = 'confirmed') => {
232
- if (!connection) {
233
- return Promise.resolve({
234
- status: 'failed' as const,
235
- error: 'Solana connection not available',
236
- })
237
- }
238
- return waitForSolanaConfirmation(
239
- signature,
240
- connection as unknown as Parameters<typeof waitForSolanaConfirmation>[1],
241
- commitment,
242
- )
243
- },
244
- [connection],
245
- )
246
-
247
- const actuallyConnected = !!address && !!connection
248
-
249
- return useMemo(
250
- () => ({
251
- isConnected: actuallyConnected,
252
- address,
253
- connection,
254
- sendTransaction,
255
- signTransaction,
256
- signMessage,
257
- state,
258
- reset,
259
- checkTxStatus,
260
- waitForConfirmation,
261
- }),
262
- [
263
- actuallyConnected,
264
- address,
265
- connection,
266
- sendTransaction,
267
- signTransaction,
268
- signMessage,
269
- state,
270
- reset,
271
- checkTxStatus,
272
- waitForConfirmation,
273
- ],
274
- )
275
- }