@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,361 +0,0 @@
1
- import type { BitcoinConnector } from '@reown/appkit-adapter-bitcoin'
2
- import type { Provider as SolanaProvider } from '@reown/appkit-adapter-solana/react'
3
- import type { AssetId, ChainId } from '@shapeshiftoss/caip'
4
- import {
5
- arbitrumChainId,
6
- avalancheChainId,
7
- baseChainId,
8
- bchChainId,
9
- bscChainId,
10
- btcChainId,
11
- CHAIN_NAMESPACE,
12
- cosmosChainId,
13
- dogeChainId,
14
- ethChainId,
15
- fromChainId,
16
- gnosisChainId,
17
- hyperEvmChainId,
18
- katanaChainId,
19
- ltcChainId,
20
- mayachainChainId,
21
- monadChainId,
22
- optimismChainId,
23
- plasmaChainId,
24
- polygonChainId,
25
- solanaChainId,
26
- thorchainChainId,
27
- worldChainChainId,
28
- } from '@shapeshiftoss/caip'
29
- import type { TransactionData } from '@shapeshiftoss/types'
30
- import { BigAmount } from '@shapeshiftoss/utils'
31
- import type { WalletClient } from 'viem'
32
- import { erc20Abi } from 'viem'
33
-
34
- export type { AssetId, ChainId }
35
- export type { BitcoinConnector }
36
- export type { SolanaProvider }
37
-
38
- export enum SwapperName {
39
- Thorchain = 'THORChain',
40
- Mayachain = 'MAYAChain',
41
- CowSwap = 'CoW Swap',
42
- Zrx = '0x',
43
- ArbitrumBridge = 'Arbitrum Bridge',
44
- Portals = 'Portals',
45
- Chainflip = 'Chainflip',
46
- Jupiter = 'Jupiter',
47
- Relay = 'Relay',
48
- ButterSwap = 'ButterSwap',
49
- Bebop = 'Bebop',
50
- NearIntents = 'NEAR Intents',
51
- Cetus = 'Cetus',
52
- Sunio = 'Sun.io',
53
- Avnu = 'AVNU',
54
- }
55
-
56
- export type Chain = {
57
- chainId: ChainId
58
- name: string
59
- icon: string
60
- color: string
61
- nativeAssetId: AssetId
62
- }
63
-
64
- export type Asset = {
65
- assetId: AssetId
66
- chainId: ChainId
67
- symbol: string
68
- name: string
69
- precision: number
70
- icon?: string
71
- color?: string
72
- networkName?: string
73
- networkIcon?: string
74
- explorer?: string
75
- explorerTxLink?: string
76
- explorerAddressLink?: string
77
- relatedAssetKey?: AssetId | null
78
- }
79
-
80
- export type TradeQuoteStep = {
81
- sellAsset: Asset
82
- buyAsset: Asset
83
- sellAmountCryptoBaseUnit: string
84
- buyAmountCryptoBaseUnit: string
85
- rate: string
86
- source: SwapperName
87
- feeData: {
88
- networkFeeCryptoBaseUnit: string
89
- protocolFees?: Record<AssetId, { amountCryptoBaseUnit: string }>
90
- }
91
- allowanceContract?: string
92
- estimatedExecutionTimeMs?: number
93
- }
94
-
95
- export type TradeQuote = {
96
- id: string
97
- rate: string
98
- swapperName: SwapperName
99
- steps: TradeQuoteStep[]
100
- receiveAddress: string
101
- affiliateBps: string
102
- slippageTolerancePercentageDecimal?: string
103
- isStreaming?: boolean
104
- }
105
-
106
- export type TradeRate = {
107
- swapperName: SwapperName
108
- rate: string
109
- buyAmountCryptoBaseUnit: string
110
- sellAmountCryptoBaseUnit: string
111
- steps: number
112
- estimatedExecutionTimeMs?: number
113
- affiliateBps: string
114
- networkFeeCryptoBaseUnit?: string
115
- error?: {
116
- code: string
117
- message: string
118
- }
119
- id?: string
120
- }
121
-
122
- export type ThemeMode = 'light' | 'dark'
123
-
124
- export type ThemeConfig = {
125
- mode: ThemeMode
126
- accentColor?: string
127
- backgroundColor?: string
128
- cardColor?: string
129
- textColor?: string
130
- borderRadius?: string
131
- fontFamily?: string
132
- borderColor?: string
133
- secondaryTextColor?: string
134
- mutedTextColor?: string
135
- inputColor?: string
136
- hoverColor?: string
137
- buttonVariant?: 'filled' | 'outline'
138
- }
139
-
140
- export type SwapWidgetProps = {
141
- affiliateAddress?: string
142
- apiBaseUrl?: string
143
- defaultSellAsset?: Asset
144
- defaultBuyAsset?: Asset
145
- disabledChainIds?: ChainId[]
146
- disabledAssetIds?: AssetId[]
147
- allowedChainIds?: ChainId[]
148
- sellDisabledChainIds?: ChainId[]
149
- buyDisabledChainIds?: ChainId[]
150
- sellDisabledAssetIds?: AssetId[]
151
- buyDisabledAssetIds?: AssetId[]
152
- sellAllowedChainIds?: ChainId[]
153
- buyAllowedChainIds?: ChainId[]
154
- sellAllowedAssetIds?: AssetId[]
155
- buyAllowedAssetIds?: AssetId[]
156
- allowedSwapperNames?: SwapperName[]
157
- walletClient?: WalletClient
158
- onConnectWallet?: () => void
159
- onSwapSuccess?: (txHash: string) => void
160
- onSwapError?: (error: Error) => void
161
- onAssetSelect?: (type: 'sell' | 'buy', asset: Asset) => void
162
- theme?: ThemeMode | ThemeConfig
163
- defaultSlippage?: string
164
- showPoweredBy?: boolean
165
- enableWalletConnection?: boolean
166
- walletConnectProjectId?: string
167
- defaultReceiveAddress?: string
168
- ratesRefetchInterval?: number
169
- isBuyAssetLocked?: boolean
170
- }
171
-
172
- export type RatesResponse = {
173
- rates: TradeRate[]
174
- }
175
-
176
- export type {
177
- CosmosTransactionData,
178
- EvmTransactionData,
179
- Permit2SignatureRequired,
180
- SolanaTransactionData,
181
- TransactionData,
182
- UtxoDepositTransactionData,
183
- UtxoPsbtTransactionData,
184
- UtxoTransactionData,
185
- } from '@shapeshiftoss/types'
186
-
187
- export type ApiQuoteStep = {
188
- sellAsset: Asset
189
- buyAsset: Asset
190
- sellAmountCryptoBaseUnit: string
191
- buyAmountAfterFeesCryptoBaseUnit: string
192
- allowanceContract: string
193
- estimatedExecutionTimeMs: number | undefined
194
- source: string
195
- transactionData?: TransactionData
196
- relayTransactionMetadata?: TransactionData
197
- butterSwapTransactionMetadata?: TransactionData
198
- solanaTransactionMetadata?: {
199
- instructions: {
200
- programId: string
201
- keys: { pubkey: string; isSigner: boolean; isWritable: boolean }[]
202
- data: { data: number[] }
203
- }[]
204
- }
205
- }
206
-
207
- export type ApprovalInfo = {
208
- isRequired: boolean
209
- spender: string
210
- approvalTx?: {
211
- to: string
212
- data: string
213
- value: string
214
- }
215
- }
216
-
217
- export type QuoteResponse = {
218
- quoteId: string
219
- swapperName: SwapperName
220
- rate: string
221
- sellAsset: Asset
222
- buyAsset: Asset
223
- sellAmountCryptoBaseUnit: string
224
- buyAmountBeforeFeesCryptoBaseUnit: string
225
- buyAmountAfterFeesCryptoBaseUnit: string
226
- affiliateBps: string
227
- slippageTolerancePercentageDecimal: string | undefined
228
- networkFeeCryptoBaseUnit: string | undefined
229
- /** @deprecated Use `quote.steps` instead. Top-level `steps` is kept for backward compatibility. */
230
- steps: ApiQuoteStep[]
231
- approval: ApprovalInfo
232
- expiresAt: number
233
- transactionData?: TransactionData
234
- quote?: {
235
- steps?: ApiQuoteStep[]
236
- }
237
- }
238
-
239
- export { erc20Abi as ERC20_ABI }
240
-
241
- export type AssetsResponse = {
242
- byId: Record<AssetId, Asset>
243
- ids: AssetId[]
244
- }
245
-
246
- export const EVM_CHAIN_IDS = {
247
- ethereum: ethChainId,
248
- arbitrum: arbitrumChainId,
249
- optimism: optimismChainId,
250
- polygon: polygonChainId,
251
- base: baseChainId,
252
- avalanche: avalancheChainId,
253
- bsc: bscChainId,
254
- gnosis: gnosisChainId,
255
- monad: monadChainId,
256
- hyperEvm: hyperEvmChainId,
257
- plasma: plasmaChainId,
258
- worldChain: worldChainChainId,
259
- katana: katanaChainId,
260
- } as const
261
-
262
- export const UTXO_CHAIN_IDS = {
263
- bitcoin: btcChainId,
264
- bitcoinCash: bchChainId,
265
- dogecoin: dogeChainId,
266
- litecoin: ltcChainId,
267
- } as const
268
-
269
- export const COSMOS_CHAIN_IDS = {
270
- cosmos: cosmosChainId,
271
- thorchain: thorchainChainId,
272
- mayachain: mayachainChainId,
273
- } as const
274
-
275
- export const OTHER_CHAIN_IDS = {
276
- solana: solanaChainId,
277
- } as const
278
-
279
- export const isEvmChainId = (chainId: string): boolean => {
280
- const { chainNamespace } = fromChainId(chainId as ChainId)
281
- return chainNamespace === CHAIN_NAMESPACE.Evm
282
- }
283
-
284
- export const getEvmNetworkId = (chainId: string): number => {
285
- const { chainReference } = fromChainId(chainId as ChainId)
286
- return parseInt(chainReference, 10)
287
- }
288
-
289
- export const getChainType = (chainId: string): 'evm' | 'utxo' | 'cosmos' | 'solana' | 'other' => {
290
- const { chainNamespace } = fromChainId(chainId as ChainId)
291
- switch (chainNamespace) {
292
- case CHAIN_NAMESPACE.Evm:
293
- return 'evm'
294
- case CHAIN_NAMESPACE.Utxo:
295
- return 'utxo'
296
- case CHAIN_NAMESPACE.CosmosSdk:
297
- return 'cosmos'
298
- case CHAIN_NAMESPACE.Solana:
299
- return 'solana'
300
- default:
301
- return 'other'
302
- }
303
- }
304
-
305
- export const formatAmount = (amount: string, decimals: number, maxDecimals?: number): string => {
306
- const effectiveMaxDecimals = maxDecimals ?? Math.min(decimals, 8)
307
- const result = BigAmount.fromBaseUnit({ value: amount, precision: decimals }).toFixed(
308
- effectiveMaxDecimals,
309
- )
310
- const num = Number(result)
311
- if (num === 0) return '0'
312
-
313
- const threshold = Math.pow(10, -effectiveMaxDecimals)
314
- if (num > 0 && num < threshold) {
315
- return `< ${threshold.toFixed(effectiveMaxDecimals)}`
316
- }
317
-
318
- return num.toLocaleString(undefined, {
319
- maximumFractionDigits: effectiveMaxDecimals,
320
- minimumFractionDigits: 0,
321
- })
322
- }
323
-
324
- export const parseAmount = (amount: string, decimals: number): string => {
325
- return BigAmount.fromPrecision({ value: amount, precision: decimals }).toBaseUnit()
326
- }
327
-
328
- export const truncateAddress = (address: string, chars = 4): string => {
329
- if (address.length <= chars * 2 + 2) return address
330
- return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`
331
- }
332
-
333
- export type TransactionStatus = 'pending' | 'confirmed' | 'failed'
334
-
335
- export type TransactionStatusResult = {
336
- status: TransactionStatus
337
- confirmations?: number
338
- blockNumber?: number
339
- error?: string
340
- }
341
-
342
- export type BitcoinTransactionStatus = {
343
- confirmed: boolean
344
- block_height?: number
345
- block_hash?: string
346
- block_time?: number
347
- }
348
-
349
- export type WalletProviderNamespace = 'eip155' | 'bip122' | 'solana'
350
-
351
- export type MultiChainAddress = {
352
- namespace: WalletProviderNamespace
353
- address: string
354
- chainId?: ChainId
355
- }
356
-
357
- export type MultiChainWalletState = {
358
- isConnected: boolean
359
- addresses: MultiChainAddress[]
360
- activeNamespace?: WalletProviderNamespace
361
- }
@@ -1,201 +0,0 @@
1
- import { bech32 } from 'bech32'
2
- import { isAddress } from 'viem'
3
-
4
- import type { ChainId } from '../types'
5
- import { COSMOS_CHAIN_IDS, getChainType } from '../types'
6
-
7
- /**
8
- * Validates a Bitcoin address (Legacy, SegWit, Native SegWit, Taproot)
9
- */
10
- export const isValidBitcoinAddress = (address: string): boolean => {
11
- // Legacy (P2PKH) - starts with 1
12
- const legacyRegex = /^1[a-km-zA-HJ-NP-Z1-9]{25,34}$/
13
- // Legacy (P2SH) - starts with 3
14
- const p2shRegex = /^3[a-km-zA-HJ-NP-Z1-9]{25,34}$/
15
- // Native SegWit (Bech32) - starts with bc1q
16
- const nativeSegwitRegex = /^bc1q[a-z0-9]{38,58}$/i
17
- // Taproot (Bech32m) - starts with bc1p
18
- const taprootRegex = /^bc1p[a-z0-9]{58}$/i
19
-
20
- return (
21
- legacyRegex.test(address) ||
22
- p2shRegex.test(address) ||
23
- nativeSegwitRegex.test(address) ||
24
- taprootRegex.test(address)
25
- )
26
- }
27
-
28
- /**
29
- * Validates a Bitcoin Cash address
30
- */
31
- export const isValidBitcoinCashAddress = (address: string): boolean => {
32
- // CashAddr format - starts with bitcoincash: or just q/p
33
- const cashAddrRegex = /^(bitcoincash:)?[qp][a-z0-9]{41}$/i
34
- // Legacy format (same as Bitcoin)
35
- const legacyRegex = /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/
36
-
37
- return cashAddrRegex.test(address) || legacyRegex.test(address)
38
- }
39
-
40
- /**
41
- * Validates a Litecoin address
42
- */
43
- export const isValidLitecoinAddress = (address: string): boolean => {
44
- // Legacy (P2PKH) - starts with L
45
- const legacyRegex = /^L[a-km-zA-HJ-NP-Z1-9]{25,34}$/
46
- // Legacy (P2SH) - starts with M or 3
47
- const p2shRegex = /^[M3][a-km-zA-HJ-NP-Z1-9]{25,34}$/
48
- // Native SegWit (Bech32) - starts with ltc1
49
- const nativeSegwitRegex = /^ltc1[a-z0-9]{38,58}$/i
50
-
51
- return legacyRegex.test(address) || p2shRegex.test(address) || nativeSegwitRegex.test(address)
52
- }
53
-
54
- /**
55
- * Validates a Dogecoin address
56
- */
57
- export const isValidDogecoinAddress = (address: string): boolean => {
58
- // P2PKH - starts with D
59
- const p2pkhRegex = /^D[5-9A-HJ-NP-U][a-km-zA-HJ-NP-Z1-9]{32}$/
60
- // P2SH - starts with 9 or A
61
- const p2shRegex = /^[9A][a-km-zA-HJ-NP-Z1-9]{33}$/
62
-
63
- return p2pkhRegex.test(address) || p2shRegex.test(address)
64
- }
65
-
66
- export const isValidCosmosAddress = (address: string, expectedPrefix?: string): boolean => {
67
- try {
68
- const decoded = bech32.decode(address)
69
- if (expectedPrefix && decoded.prefix !== expectedPrefix) {
70
- return false
71
- }
72
- return true
73
- } catch {
74
- return false
75
- }
76
- }
77
-
78
- /**
79
- * Gets the expected bech32 prefix for a Cosmos chain
80
- */
81
- const getCosmosPrefix = (chainId: ChainId): string | undefined => {
82
- const prefixMap: Record<string, string> = {
83
- [COSMOS_CHAIN_IDS.cosmos]: 'cosmos',
84
- [COSMOS_CHAIN_IDS.thorchain]: 'thor',
85
- [COSMOS_CHAIN_IDS.mayachain]: 'maya',
86
- }
87
- return prefixMap[chainId]
88
- }
89
-
90
- /**
91
- * Validates a Solana address (base58, 32-44 chars)
92
- */
93
- export const isValidSolanaAddress = (address: string): boolean => {
94
- // Solana addresses are base58 encoded, typically 32-44 characters
95
- // Base58 alphabet excludes 0, O, I, l
96
- const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/
97
- return base58Regex.test(address)
98
- }
99
-
100
- /**
101
- * Validates an address for a specific chain
102
- */
103
- export const validateAddress = (
104
- address: string,
105
- chainId: ChainId,
106
- ): { valid: boolean; error?: string } => {
107
- if (!address || address.trim() === '') {
108
- return { valid: false, error: 'Address is required' }
109
- }
110
-
111
- const trimmedAddress = address.trim()
112
- const chainType = getChainType(chainId)
113
-
114
- switch (chainType) {
115
- case 'evm':
116
- if (!isAddress(trimmedAddress, { strict: false })) {
117
- return { valid: false, error: 'Invalid EVM address' }
118
- }
119
- break
120
-
121
- case 'utxo':
122
- // Determine specific UTXO chain
123
- if (chainId.includes('000000000019d6689c085ae165831e93')) {
124
- // Bitcoin
125
- if (!isValidBitcoinAddress(trimmedAddress)) {
126
- return { valid: false, error: 'Invalid Bitcoin address' }
127
- }
128
- } else if (chainId.includes('000000000000000000651ef99cb9fcbe')) {
129
- // Bitcoin Cash
130
- if (!isValidBitcoinCashAddress(trimmedAddress)) {
131
- return { valid: false, error: 'Invalid Bitcoin Cash address' }
132
- }
133
- } else if (chainId.includes('12a765e31ffd4059bada1e25190f6e98')) {
134
- // Litecoin
135
- if (!isValidLitecoinAddress(trimmedAddress)) {
136
- return { valid: false, error: 'Invalid Litecoin address' }
137
- }
138
- } else if (chainId.includes('00000000001a91e3dace36e2be3bf030')) {
139
- // Dogecoin
140
- if (!isValidDogecoinAddress(trimmedAddress)) {
141
- return { valid: false, error: 'Invalid Dogecoin address' }
142
- }
143
- } else {
144
- return { valid: false, error: 'Unsupported UTXO chain' }
145
- }
146
- break
147
-
148
- case 'cosmos': {
149
- const expectedPrefix = getCosmosPrefix(chainId)
150
- if (!isValidCosmosAddress(trimmedAddress, expectedPrefix)) {
151
- const chainName = expectedPrefix
152
- ? expectedPrefix.charAt(0).toUpperCase() + expectedPrefix.slice(1)
153
- : 'Cosmos'
154
- return { valid: false, error: `Invalid ${chainName} address` }
155
- }
156
- break
157
- }
158
-
159
- case 'solana':
160
- if (!isValidSolanaAddress(trimmedAddress)) {
161
- return { valid: false, error: 'Invalid Solana address' }
162
- }
163
- break
164
-
165
- default:
166
- return { valid: false, error: 'Unsupported chain type' }
167
- }
168
-
169
- return { valid: true }
170
- }
171
-
172
- /**
173
- * Gets the expected address format hint for a chain
174
- */
175
- export const getAddressFormatHint = (chainId: ChainId): string => {
176
- const chainType = getChainType(chainId)
177
-
178
- switch (chainType) {
179
- case 'evm':
180
- return '0x...'
181
- case 'utxo':
182
- if (chainId.includes('000000000019d6689c085ae165831e93')) {
183
- return 'bc1... or 1... or 3...'
184
- } else if (chainId.includes('000000000000000000651ef99cb9fcbe')) {
185
- return 'bitcoincash:q... or 1...'
186
- } else if (chainId.includes('12a765e31ffd4059bada1e25190f6e98')) {
187
- return 'ltc1... or L... or M...'
188
- } else if (chainId.includes('00000000001a91e3dace36e2be3bf030')) {
189
- return 'D...'
190
- }
191
- return 'Enter address'
192
- case 'cosmos': {
193
- const prefix = getCosmosPrefix(chainId)
194
- return prefix ? `${prefix}1...` : 'Enter address'
195
- }
196
- case 'solana':
197
- return 'Enter Solana address'
198
- default:
199
- return 'Enter address'
200
- }
201
- }
@@ -1,45 +0,0 @@
1
- import type { Asset, AssetId } from '../types'
2
- import { isEvmChainId } from '../types'
3
-
4
- const SHAPESHIFT_APP_URL = 'https://app.shapeshift.com'
5
-
6
- export type RedirectParams = {
7
- sellAssetId: AssetId
8
- buyAssetId: AssetId
9
- sellAmount?: string
10
- }
11
-
12
- export const buildShapeShiftTradeUrl = (params: RedirectParams): string => {
13
- const url = new URL(`${SHAPESHIFT_APP_URL}/trade`)
14
- url.searchParams.set('sellAssetId', params.sellAssetId)
15
- url.searchParams.set('buyAssetId', params.buyAssetId)
16
- if (params.sellAmount) {
17
- url.searchParams.set('sellAmount', params.sellAmount)
18
- }
19
- return url.toString()
20
- }
21
-
22
- export const redirectToShapeShift = (params: RedirectParams): void => {
23
- const url = buildShapeShiftTradeUrl(params)
24
- window.open(url, '_blank', 'noopener,noreferrer')
25
- }
26
-
27
- export type ChainType = 'evm' | 'utxo' | 'cosmos' | 'solana' | 'other'
28
-
29
- export const getChainTypeFromAsset = (asset: Asset): ChainType => {
30
- const chainId = asset.chainId
31
-
32
- if (isEvmChainId(chainId)) return 'evm'
33
- if (chainId.startsWith('bip122:')) return 'utxo'
34
- if (chainId.startsWith('cosmos:')) return 'cosmos'
35
- if (chainId.startsWith('solana:')) return 'solana'
36
-
37
- return 'other'
38
- }
39
-
40
- export const canExecuteInWidget = (sellAsset: Asset, buyAsset: Asset): boolean => {
41
- const sellChainType = getChainTypeFromAsset(sellAsset)
42
- const buyChainType = getChainTypeFromAsset(buyAsset)
43
-
44
- return sellChainType === 'evm' && buyChainType === 'evm'
45
- }
package/src/vite-env.d.ts DELETED
@@ -1,10 +0,0 @@
1
- /// <reference types="vite/client" />
2
-
3
- interface EthereumProvider {
4
- request: (args: { method: string; params?: unknown[] }) => Promise<unknown>
5
- on: (event: string, callback: (accounts: string[]) => void) => void
6
- }
7
-
8
- interface Window {
9
- ethereum?: EthereumProvider
10
- }
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "useDefineForClassFields": true,
5
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
- "module": "ESNext",
7
- "skipLibCheck": true,
8
-
9
- "moduleResolution": "bundler",
10
- "allowImportingTsExtensions": true,
11
- "resolveJsonModule": true,
12
- "isolatedModules": true,
13
- "noEmit": true,
14
- "jsx": "react-jsx",
15
-
16
- "strict": true,
17
- "noUnusedLocals": true,
18
- "noUnusedParameters": true,
19
- "noFallthroughCasesInSwitch": true
20
- },
21
- "include": ["src"],
22
- "references": [{ "path": "./tsconfig.node.json" }]
23
- }
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "composite": true,
4
- "skipLibCheck": true,
5
- "module": "ESNext",
6
- "moduleResolution": "bundler",
7
- "allowSyntheticDefaultImports": true
8
- },
9
- "include": ["vite.config.ts"]
10
- }