@openocean.finance/widget 1.0.28 → 1.0.30

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 (109) hide show
  1. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +46 -39
  2. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
  3. package/dist/esm/components/Messages/WarningMessages.js +2 -2
  4. package/dist/esm/components/Messages/WarningMessages.js.map +1 -1
  5. package/dist/esm/components/Step/Step.js +37 -29
  6. package/dist/esm/components/Step/Step.js.map +1 -1
  7. package/dist/esm/components/TransactionDetails.js +3 -6
  8. package/dist/esm/components/TransactionDetails.js.map +1 -1
  9. package/dist/esm/config/version.d.ts +1 -1
  10. package/dist/esm/config/version.js +1 -1
  11. package/dist/esm/cross/adapters/AcrossAdapter.d.ts +15 -0
  12. package/dist/esm/cross/adapters/AcrossAdapter.js +166 -0
  13. package/dist/esm/cross/adapters/AcrossAdapter.js.map +1 -0
  14. package/dist/esm/cross/adapters/BaseSwapAdapter.d.ts +107 -0
  15. package/dist/esm/cross/adapters/BaseSwapAdapter.js +44 -0
  16. package/dist/esm/cross/adapters/BaseSwapAdapter.js.map +1 -0
  17. package/dist/esm/cross/adapters/DebridgeAdapter.d.ts +20 -0
  18. package/dist/esm/cross/adapters/DebridgeAdapter.js +264 -0
  19. package/dist/esm/cross/adapters/DebridgeAdapter.js.map +1 -0
  20. package/dist/esm/cross/adapters/LifiAdapter.d.ts +19 -0
  21. package/dist/esm/cross/adapters/LifiAdapter.js +169 -0
  22. package/dist/esm/cross/adapters/LifiAdapter.js.map +1 -0
  23. package/dist/esm/cross/adapters/MayanAdapter.d.ts +14 -0
  24. package/dist/esm/cross/adapters/MayanAdapter.js +119 -0
  25. package/dist/esm/cross/adapters/MayanAdapter.js.map +1 -0
  26. package/dist/esm/cross/adapters/NearIntentsAdapter.d.ts +21 -0
  27. package/dist/esm/cross/adapters/NearIntentsAdapter.js +425 -0
  28. package/dist/esm/cross/adapters/NearIntentsAdapter.js.map +1 -0
  29. package/dist/esm/cross/adapters/OptimexAdapter.d.ts +19 -0
  30. package/dist/esm/cross/adapters/OptimexAdapter.js +216 -0
  31. package/dist/esm/cross/adapters/OptimexAdapter.js.map +1 -0
  32. package/dist/esm/cross/adapters/OrbiterAdapter.d.ts +20 -0
  33. package/dist/esm/cross/adapters/OrbiterAdapter.js +213 -0
  34. package/dist/esm/cross/adapters/OrbiterAdapter.js.map +1 -0
  35. package/dist/esm/cross/adapters/RelayAdapter.d.ts +14 -0
  36. package/dist/esm/cross/adapters/RelayAdapter.js +171 -0
  37. package/dist/esm/cross/adapters/RelayAdapter.js.map +1 -0
  38. package/dist/esm/cross/adapters/SymbiosisAdapter.d.ts +14 -0
  39. package/dist/esm/cross/adapters/SymbiosisAdapter.js +120 -0
  40. package/dist/esm/cross/adapters/SymbiosisAdapter.js.map +1 -0
  41. package/dist/esm/cross/adapters/XYFinanceAdapter.d.ts +14 -0
  42. package/dist/esm/cross/adapters/XYFinanceAdapter.js +177 -0
  43. package/dist/esm/cross/adapters/XYFinanceAdapter.js.map +1 -0
  44. package/dist/esm/cross/adapters/index.d.ts +2 -0
  45. package/dist/esm/cross/adapters/index.js +10 -0
  46. package/dist/esm/cross/adapters/index.js.map +1 -0
  47. package/dist/esm/cross/constants/index.d.ts +202 -0
  48. package/dist/esm/cross/constants/index.js +183 -0
  49. package/dist/esm/cross/constants/index.js.map +1 -0
  50. package/dist/esm/cross/crossChainQuote.d.ts +25 -0
  51. package/dist/esm/cross/crossChainQuote.js +127 -0
  52. package/dist/esm/cross/crossChainQuote.js.map +1 -0
  53. package/dist/esm/cross/factory.d.ts +9 -0
  54. package/dist/esm/cross/factory.js +125 -0
  55. package/dist/esm/cross/factory.js.map +1 -0
  56. package/dist/esm/cross/registry.d.ts +12 -0
  57. package/dist/esm/cross/registry.js +52 -0
  58. package/dist/esm/cross/registry.js.map +1 -0
  59. package/dist/esm/hooks/useChain.d.ts +1 -1
  60. package/dist/esm/hooks/useGasRefuel.d.ts +1 -1
  61. package/dist/esm/hooks/useGasSufficiencyBridge.js +1 -2
  62. package/dist/esm/hooks/useGasSufficiencyBridge.js.map +1 -1
  63. package/dist/esm/hooks/useRouteExecution.js +2 -1
  64. package/dist/esm/hooks/useRouteExecution.js.map +1 -1
  65. package/dist/esm/hooks/useRoutes.js +49 -33
  66. package/dist/esm/hooks/useRoutes.js.map +1 -1
  67. package/dist/esm/hooks/useSettingMonitor.js.map +1 -1
  68. package/dist/esm/hooks/useTokenAddressBalance.d.ts +1 -1
  69. package/dist/esm/hooks/useTokenPrice.js +4 -2
  70. package/dist/esm/hooks/useTokenPrice.js.map +1 -1
  71. package/dist/esm/hooks/useTokens.d.ts +1 -1
  72. package/dist/esm/services/ExecuteRoute.js +142 -124
  73. package/dist/esm/services/ExecuteRoute.js.map +1 -1
  74. package/dist/esm/stores/form/useFieldController.d.ts +1 -1
  75. package/dist/esm/stores/routes/createRouteExecutionStore.js +6 -3
  76. package/dist/esm/stores/routes/createRouteExecutionStore.js.map +1 -1
  77. package/dist/esm/stores/routes/useSetExecutableRoute.d.ts +1 -1
  78. package/dist/esm/types/widget.d.ts +3 -0
  79. package/dist/tsconfig.tsbuildinfo +1 -0
  80. package/package.json +14 -4
  81. package/src/components/AmountInput/AmountInputEndAdornment.tsx +46 -46
  82. package/src/components/Messages/WarningMessages.tsx +7 -2
  83. package/src/components/Step/Step.tsx +37 -31
  84. package/src/components/TransactionDetails.tsx +11 -12
  85. package/src/config/version.ts +1 -1
  86. package/src/cross/adapters/AcrossAdapter.ts +193 -0
  87. package/src/cross/adapters/BaseSwapAdapter.ts +173 -0
  88. package/src/cross/adapters/DebridgeAdapter.ts +375 -0
  89. package/src/cross/adapters/LifiAdapter.ts +213 -0
  90. package/src/cross/adapters/MayanAdapter.ts +179 -0
  91. package/src/cross/adapters/NearIntentsAdapter.ts +539 -0
  92. package/src/cross/adapters/OptimexAdapter.ts +273 -0
  93. package/src/cross/adapters/OrbiterAdapter.ts +270 -0
  94. package/src/cross/adapters/RelayAdapter.ts +248 -0
  95. package/src/cross/adapters/SymbiosisAdapter.ts +144 -0
  96. package/src/cross/adapters/XYFinanceAdapter.ts +213 -0
  97. package/src/cross/adapters/index.ts +9 -0
  98. package/src/cross/constants/index.ts +223 -0
  99. package/src/cross/crossChainQuote.ts +181 -0
  100. package/src/cross/factory.ts +145 -0
  101. package/src/cross/registry.ts +65 -0
  102. package/src/hooks/useGasSufficiencyBridge.ts +1 -3
  103. package/src/hooks/useRouteExecution.ts +2 -1
  104. package/src/hooks/useRoutes.ts +63 -44
  105. package/src/hooks/useSettingMonitor.ts +0 -1
  106. package/src/hooks/useTokenPrice.ts +5 -3
  107. package/src/services/ExecuteRoute.ts +184 -171
  108. package/src/stores/routes/createRouteExecutionStore.ts +13 -4
  109. package/src/types/widget.ts +3 -0
@@ -0,0 +1,375 @@
1
+ import type { useWalletSelector } from '@near-wallet-selector/react-hook'
2
+ import { ChainId } from '@openocean.finance/widget-sdk'
3
+ import type { WalletAdapterProps } from '@solana/wallet-adapter-base'
4
+ import {
5
+ type Connection,
6
+ Transaction,
7
+ VersionedTransaction,
8
+ } from '@solana/web3.js'
9
+ import { type WalletClient, formatUnits } from 'viem'
10
+ import type { Currency } from '../constants/index.js'
11
+
12
+ import { TOKEN_API_URL } from '../constants/index.js'
13
+ import {
14
+ CROSS_CHAIN_FEE_RECEIVER,
15
+ CROSS_CHAIN_FEE_RECEIVER_SOLANA,
16
+ ZERO_ADDRESS,
17
+ } from '../constants/index.js'
18
+ import { NativeCurrencies } from '../constants/index.js'
19
+ import type { SolanaToken } from '../constants/index.js'
20
+
21
+ import type { Quote } from '../registry.js'
22
+ import {
23
+ BaseSwapAdapter,
24
+ type Chain,
25
+ NOT_SUPPORTED_CHAINS_PRICE_SERVICE,
26
+ NonEvmChain,
27
+ type NormalizedQuote,
28
+ type NormalizedTxResponse,
29
+ type QuoteParams,
30
+ type SwapStatus,
31
+ } from './BaseSwapAdapter.js'
32
+
33
+ const DEBRIDGE_API = 'https://dln.debridge.finance/v1.0/dln/order'
34
+
35
+ const mappingChainId: Record<string, number> = {
36
+ [ChainId.DAI]: 100000002,
37
+ [ChainId.MAM]: 100000004, // Metis
38
+ [ChainId.SON]: 100000014, // Sonic
39
+ [ChainId.ABS]: 100000017, // Abstract
40
+ [ChainId.BER]: 100000020, // Berachain
41
+ [ChainId.BOB]: 100000021, // BOB
42
+ [ChainId.MNT]: 100000023, // Mantle
43
+ [NonEvmChain.Solana]: 7565164,
44
+ }
45
+
46
+ export class DeBridgeAdapter extends BaseSwapAdapter {
47
+ constructor() {
48
+ super()
49
+ }
50
+
51
+ getName(): string {
52
+ return 'deBridge'
53
+ }
54
+ getIcon(): string {
55
+ return 'https://app.debridge.finance/assets/images/meta-deswap/favicon-32x32.png'
56
+ }
57
+ getSupportedChains(): Chain[] {
58
+ return [
59
+ ChainId.ETH,
60
+ ChainId.BSC,
61
+ ChainId.POL,
62
+ ChainId.AVA,
63
+ ChainId.ARB,
64
+ ChainId.OPT,
65
+ ChainId.ONE,
66
+ ChainId.FSN,
67
+ ChainId.MOR,
68
+ ChainId.CEL,
69
+ ChainId.FUS,
70
+ ChainId.TLO,
71
+ ChainId.CRO,
72
+ ChainId.BOB,
73
+ ChainId.RSK,
74
+ ChainId.VEL,
75
+ ChainId.MOO,
76
+ ChainId.MAM,
77
+ ChainId.AUR,
78
+ ChainId.EVM,
79
+ ChainId.ARN,
80
+ ChainId.ERA,
81
+ ChainId.PZE,
82
+ ChainId.LNA,
83
+ ChainId.BAS,
84
+ ChainId.SCL,
85
+ ChainId.MOD,
86
+ ChainId.MNT,
87
+ ChainId.BLS,
88
+ ChainId.SEI,
89
+ ChainId.FRA,
90
+ ChainId.TAI,
91
+ ChainId.GRA,
92
+ ChainId.IMX,
93
+ ChainId.KAI,
94
+ ChainId.XLY,
95
+ // NonEvmChain.Solana,
96
+ ]
97
+ }
98
+
99
+ getSupportedTokens(_sourceChain: Chain, _destChain: Chain): Currency[] {
100
+ return []
101
+ }
102
+
103
+ async getQuote(params: QuoteParams): Promise<NormalizedQuote> {
104
+ const fromToken = params.fromToken as any
105
+ const toToken = params.toToken as any
106
+
107
+ let p: Record<string, string | boolean | number> = {
108
+ srcChainId: mappingChainId[params.fromChain] || params.fromChain,
109
+ srcChainTokenIn:
110
+ params.fromChain === 'solana'
111
+ ? (params.fromToken as SolanaToken).id
112
+ : fromToken.isNative
113
+ ? ZERO_ADDRESS
114
+ : fromToken.address,
115
+
116
+ srcChainTokenInAmount: params.amount,
117
+
118
+ dstChainId: mappingChainId[params.toChain] || params.toChain,
119
+ dstChainTokenOut:
120
+ params.toChain === 'solana'
121
+ ? (params.toToken as SolanaToken).id
122
+ : toToken.isNative
123
+ ? ZERO_ADDRESS
124
+ : toToken.address,
125
+
126
+ dstChainTokenOutAmount: 'auto',
127
+
128
+ enableEstimate: false,
129
+ prependOperatingExpenses: false,
130
+
131
+ referralCode: 31982,
132
+ affiliateFeePercent: (params.feeBps * 100) / 10_000,
133
+ affiliateFeeRecipient:
134
+ params.fromChain === 'solana'
135
+ ? CROSS_CHAIN_FEE_RECEIVER_SOLANA
136
+ : CROSS_CHAIN_FEE_RECEIVER,
137
+ }
138
+
139
+ let path = 'quote'
140
+ if (params.recipient && params.sender && params.sender !== ZERO_ADDRESS) {
141
+ path = 'create-tx'
142
+ p = {
143
+ ...p,
144
+ srcChainOrderAuthorityAddress: params.sender,
145
+ dstChainOrderAuthorityAddress: params.recipient,
146
+ dstChainTokenOutRecipient: params.recipient,
147
+ }
148
+ }
149
+
150
+ // Convert the parameters object to URL query string
151
+ const queryParams = new URLSearchParams()
152
+ for (const [key, value] of Object.entries(p)) {
153
+ queryParams.append(key, String(value))
154
+ }
155
+
156
+ const r = await fetch(
157
+ `${DEBRIDGE_API}/${path}?${queryParams.toString()}`
158
+ ).then((res) => res.json())
159
+ if (!r.estimation) {
160
+ throw new Error(r.errorMessage)
161
+ }
162
+
163
+ //const inputUsd = r.estimation.srcChainTokenIn.approximateUsdValue
164
+ //const outputUsd = r.estimation.dstChainTokenOut.recommendedApproximateUsdValue
165
+
166
+ const formattedInputAmount = formatUnits(
167
+ BigInt(params.amount),
168
+ params.fromToken.decimals
169
+ )
170
+ const formattedOutputAmount = formatUnits(
171
+ BigInt(r.estimation.dstChainTokenOut.recommendedAmount),
172
+ params.toToken.decimals
173
+ )
174
+
175
+ const inputUsd = NOT_SUPPORTED_CHAINS_PRICE_SERVICE.includes(
176
+ params.fromChain
177
+ )
178
+ ? r.estimation.srcChainTokenIn.approximateUsdValue
179
+ : params.tokenInUsd * +formattedInputAmount
180
+ const outputUsd = NOT_SUPPORTED_CHAINS_PRICE_SERVICE.includes(
181
+ params.toChain
182
+ )
183
+ ? r.estimation.dstChainTokenOut.recommendedApproximateUsdValue
184
+ : params.tokenOutUsd * +formattedOutputAmount
185
+
186
+ const fixFee = r.fixFee
187
+
188
+ const wrappedAddress =
189
+ NativeCurrencies[params.fromChain as ChainId].wrapped.address
190
+ const nativePrice = await fetch(
191
+ `${TOKEN_API_URL}/v1/public/tokens/prices`,
192
+ {
193
+ method: 'POST',
194
+ body: JSON.stringify({
195
+ [params.fromChain]: [wrappedAddress],
196
+ }),
197
+ }
198
+ )
199
+ .then((res) => res.json())
200
+ .then((res) => {
201
+ return res?.data?.[params.fromChain]?.[wrappedAddress]?.PriceBuy || 0
202
+ })
203
+
204
+ const nativeDecimals =
205
+ params.fromChain === 'solana'
206
+ ? 9
207
+ : NativeCurrencies[params.fromChain as ChainId].decimals
208
+ const protocolFee =
209
+ Number(nativePrice) * (Number(fixFee) / 10 ** nativeDecimals)
210
+ const protocolFeeString = `${Number(fixFee) / 10 ** nativeDecimals} ${
211
+ params.fromChain === 'solana'
212
+ ? 'SOL'
213
+ : NativeCurrencies[params.fromChain as ChainId].symbol
214
+ }`
215
+
216
+ return {
217
+ quoteParams: params,
218
+ outputAmount: BigInt(r.estimation.dstChainTokenOut.recommendedAmount),
219
+
220
+ formattedOutputAmount,
221
+
222
+ inputUsd,
223
+ outputUsd,
224
+
225
+ priceImpact:
226
+ !inputUsd || !outputUsd
227
+ ? Number.NaN
228
+ : ((inputUsd - outputUsd) * 100) / inputUsd,
229
+ rate: +formattedOutputAmount / +formattedInputAmount,
230
+
231
+ gasFeeUsd: 0,
232
+ timeEstimate: r.order.approximateFulfillmentDelay,
233
+ contractAddress: r.tx.allowanceTarget || r.tx.to,
234
+ rawQuote: r,
235
+
236
+ protocolFee,
237
+ protocolFeeString,
238
+ platformFeePercent: (params.feeBps * 100) / 10_000,
239
+ }
240
+ }
241
+
242
+ async executeSwap(
243
+ { quote }: Quote,
244
+ walletClient: WalletClient,
245
+ _nearWallet?: ReturnType<typeof useWalletSelector>,
246
+ _sendBtcFn?: (params: {
247
+ recipient: string
248
+ amount: string | number
249
+ }) => Promise<string>,
250
+ sendSolanaFn?: WalletAdapterProps['sendTransaction'],
251
+ solanaConnection?: Connection
252
+ ): Promise<NormalizedTxResponse> {
253
+ if (quote.quoteParams.fromChain === 'solana') {
254
+ if (!solanaConnection || !sendSolanaFn)
255
+ throw new Error('Connection is not defined for Solana swap')
256
+ const txBuffer = Buffer.from(quote.rawQuote.tx.data.slice(2), 'hex')
257
+
258
+ // Try to deserialize as VersionedTransaction first
259
+ let transaction
260
+ try {
261
+ transaction = VersionedTransaction.deserialize(txBuffer)
262
+ console.log('Parsed as VersionedTransaction')
263
+ } catch (versionedError) {
264
+ console.log(
265
+ 'Failed to parse as VersionedTransaction, trying legacy Transaction'
266
+ )
267
+ try {
268
+ transaction = Transaction.from(txBuffer)
269
+ console.log('Parsed as legacy Transaction')
270
+ } catch (legacyError) {
271
+ throw new Error(
272
+ 'Could not parse transaction as either VersionedTransaction or legacy Transaction'
273
+ )
274
+ }
275
+ }
276
+
277
+ console.log('Transaction parsed successfully:', transaction)
278
+
279
+ // Send through wallet adapter
280
+ const signature = await sendSolanaFn(transaction, solanaConnection)
281
+ const waitForConfirmation = async (txId: string) => {
282
+ try {
283
+ const latestBlockhash = await solanaConnection.getLatestBlockhash()
284
+
285
+ // Wait for confirmation with timeout
286
+ const confirmation = await Promise.race([
287
+ solanaConnection.confirmTransaction(
288
+ {
289
+ signature: txId,
290
+ blockhash: latestBlockhash.blockhash,
291
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
292
+ },
293
+ 'confirmed'
294
+ ),
295
+ new Promise((_, reject) =>
296
+ setTimeout(
297
+ () => reject(new Error('Transaction confirmation timeout')),
298
+ 60000
299
+ )
300
+ ),
301
+ ])
302
+
303
+ const confirmationResult = confirmation as { value: { err: any } }
304
+ if (confirmationResult.value.err) {
305
+ throw new Error(
306
+ `Transaction failed: ${JSON.stringify(confirmationResult.value.err)}`
307
+ )
308
+ }
309
+
310
+ console.log('Transaction confirmed successfully!')
311
+ } catch (confirmError) {
312
+ console.error('Transaction confirmation failed:', confirmError)
313
+
314
+ // Check if transaction actually succeeded despite timeout
315
+ const txStatus = await solanaConnection.getSignatureStatus(txId)
316
+ if (txStatus?.value?.confirmationStatus !== 'confirmed') {
317
+ throw new Error(
318
+ `Transaction was not confirmed: ${confirmError.message}`
319
+ )
320
+ }
321
+ }
322
+ }
323
+
324
+ await waitForConfirmation(signature)
325
+
326
+ return {
327
+ sender: quote.quoteParams.sender,
328
+ id: quote.rawQuote.orderId, // specific id for debridge
329
+ sourceTxHash: signature,
330
+ adapter: this.getName(),
331
+ sourceChain: quote.quoteParams.fromChain,
332
+ targetChain: quote.quoteParams.toChain,
333
+ inputAmount: quote.quoteParams.amount,
334
+ outputAmount: quote.outputAmount.toString(),
335
+ sourceToken: quote.quoteParams.fromToken,
336
+ targetToken: quote.quoteParams.toToken,
337
+ timestamp: new Date().getTime(),
338
+ }
339
+ }
340
+
341
+ const account = walletClient.account?.address
342
+ if (!account) throw new Error('WalletClient account is not defined')
343
+
344
+ const tx = await walletClient.sendTransaction({
345
+ chain: undefined,
346
+ account,
347
+ to: quote.rawQuote.tx.to,
348
+ value: BigInt(quote.rawQuote.tx.value),
349
+ data: quote.rawQuote.tx.data,
350
+ })
351
+ return {
352
+ sender: quote.quoteParams.sender,
353
+ id: quote.rawQuote.orderId, // specific id for each provider
354
+ sourceTxHash: tx,
355
+ adapter: this.getName(),
356
+ sourceChain: quote.quoteParams.fromChain,
357
+ targetChain: quote.quoteParams.toChain,
358
+ inputAmount: quote.quoteParams.amount,
359
+ outputAmount: quote.outputAmount.toString(),
360
+ sourceToken: quote.quoteParams.fromToken,
361
+ targetToken: quote.quoteParams.toToken,
362
+ timestamp: new Date().getTime(),
363
+ }
364
+ }
365
+
366
+ async getTransactionStatus(p: NormalizedTxResponse): Promise<SwapStatus> {
367
+ const r = await fetch(`${DEBRIDGE_API}/${p.id}/status`).then((res) =>
368
+ res.json()
369
+ )
370
+ return {
371
+ status: r.status === 'Fulfilled' ? 'Success' : 'Processing',
372
+ txHash: p.id,
373
+ }
374
+ }
375
+ }
@@ -0,0 +1,213 @@
1
+ import { createConfig, getQuote, getStatus } from '@lifi/sdk'
2
+ import { WalletAdapterProps } from '@solana/wallet-adapter-base'
3
+ import { Connection, Transaction, VersionedTransaction } from '@solana/web3.js'
4
+ import { WalletClient, formatUnits } from 'viem'
5
+
6
+ import { CROSS_CHAIN_FEE_RECEIVER, ZERO_ADDRESS, Currency, SolanaToken, MAINNET_NETWORKS } from '../constants/index.js'
7
+
8
+ import { Quote } from '../registry.js'
9
+ import {
10
+ BaseSwapAdapter,
11
+ Chain,
12
+ NOT_SUPPORTED_CHAINS_PRICE_SERVICE,
13
+ NonEvmChain,
14
+ NormalizedQuote,
15
+ NormalizedTxResponse,
16
+ QuoteParams,
17
+ SwapStatus,
18
+ } from './BaseSwapAdapter.js'
19
+
20
+ export class LifiAdapter extends BaseSwapAdapter {
21
+ constructor() {
22
+ super()
23
+ createConfig({
24
+ integrator: 'kyberswap',
25
+ })
26
+ }
27
+
28
+ getName(): string {
29
+ return 'LIFI'
30
+ }
31
+ getIcon(): string {
32
+ return 'https://storage.googleapis.com/ks-setting-1d682dca/aed3a971-48be-4c3c-9597-5ab78073fbf11745552578218.png'
33
+ }
34
+ getSupportedChains(): Chain[] {
35
+ return [NonEvmChain.Solana, ...MAINNET_NETWORKS]
36
+ }
37
+
38
+ getSupportedTokens(_sourceChain: Chain, _destChain: Chain): Currency[] {
39
+ return []
40
+ }
41
+
42
+ async getQuote(params: QuoteParams): Promise<NormalizedQuote> {
43
+ const r = await getQuote({
44
+ fromChain: params.fromChain === 'solana' ? 'SOL' : +params.fromChain, // Arbitrum
45
+ fromToken:
46
+ params.fromChain === 'solana'
47
+ ? (params.fromToken as SolanaToken).id
48
+ : (params.fromToken as any).isNative
49
+ ? ZERO_ADDRESS
50
+ : (params.fromToken as any).wrapped.address,
51
+ fromAmount: params.amount,
52
+ fromAddress: params.sender === ZERO_ADDRESS ? CROSS_CHAIN_FEE_RECEIVER : params.sender,
53
+
54
+ toChain: params.toChain === 'solana' ? 'SOL' : +params.toChain,
55
+ toToken:
56
+ params.toChain === 'solana'
57
+ ? (params.toToken as SolanaToken).id
58
+ : (params.toToken as any).isNative
59
+ ? ZERO_ADDRESS
60
+ : (params.toToken as any).wrapped.address,
61
+ toAddress: params.recipient,
62
+ fee: params.feeBps / 10_000,
63
+ })
64
+
65
+ //const inputUsd = Number(r.estimate.fromAmountUSD || '0')
66
+ //const outputUsd = Number(r.estimate.toAmountUSD || '0')
67
+ const formattedOutputAmount = formatUnits(BigInt(r.estimate.toAmount), params.toToken.decimals)
68
+ const formattedInputAmount = formatUnits(BigInt(params.amount), params.fromToken.decimals)
69
+
70
+ const inputUsd = NOT_SUPPORTED_CHAINS_PRICE_SERVICE.includes(params.fromChain)
71
+ ? Number(r.estimate.fromAmountUSD)
72
+ : params.tokenInUsd * +formattedInputAmount
73
+ const outputUsd = NOT_SUPPORTED_CHAINS_PRICE_SERVICE.includes(params.toChain)
74
+ ? Number(r.estimate.toAmountUSD)
75
+ : params.tokenOutUsd * +formattedOutputAmount
76
+
77
+ return {
78
+ quoteParams: params,
79
+ outputAmount: BigInt(r.estimate.toAmount),
80
+ formattedOutputAmount: formatUnits(BigInt(r.estimate.toAmount), params.toToken.decimals),
81
+ inputUsd,
82
+ outputUsd,
83
+
84
+ priceImpact: !inputUsd || !outputUsd ? NaN : ((inputUsd - outputUsd) * 100) / inputUsd,
85
+ rate: +formattedOutputAmount / +formattedInputAmount,
86
+
87
+ gasFeeUsd: 0,
88
+
89
+ timeEstimate: r.estimate.executionDuration,
90
+ contractAddress: r.transactionRequest?.to || r.estimate.approvalAddress,
91
+ rawQuote: r,
92
+
93
+ protocolFee: 0,
94
+ platformFeePercent: (params.feeBps * 100) / 10_000,
95
+ }
96
+ }
97
+
98
+ async executeSwap(
99
+ { quote }: Quote,
100
+ walletClient: WalletClient,
101
+ _nearWalletClient?: any,
102
+ _sendBtcFn?: (params: { recipient: string; amount: string | number }) => Promise<string>,
103
+ sendTransaction?: WalletAdapterProps['sendTransaction'],
104
+ connection?: Connection,
105
+ ): Promise<NormalizedTxResponse> {
106
+ if (quote.quoteParams.fromChain === NonEvmChain.Solana) {
107
+ if (!connection || !sendTransaction) throw new Error('Connection is not defined for Solana swap')
108
+ const txBuffer = Buffer.from(quote.rawQuote.transactionRequest.data, 'base64')
109
+
110
+ // Try to deserialize as VersionedTransaction first
111
+ let transaction
112
+ try {
113
+ transaction = VersionedTransaction.deserialize(txBuffer)
114
+ console.log('Parsed as VersionedTransaction')
115
+ } catch (versionedError) {
116
+ console.log('Failed to parse as VersionedTransaction, trying legacy Transaction')
117
+ try {
118
+ transaction = Transaction.from(txBuffer)
119
+ console.log('Parsed as legacy Transaction')
120
+ } catch (legacyError) {
121
+ throw new Error('Could not parse transaction as either VersionedTransaction or legacy Transaction')
122
+ }
123
+ }
124
+
125
+ console.log('Transaction parsed successfully:', transaction)
126
+
127
+ // Send through wallet adapter
128
+ const signature = await sendTransaction(transaction, connection)
129
+
130
+ try {
131
+ const latestBlockhash = await connection.getLatestBlockhash()
132
+
133
+ // Wait for confirmation with timeout
134
+ const confirmation = await Promise.race([
135
+ connection.confirmTransaction(
136
+ {
137
+ signature,
138
+ blockhash: latestBlockhash.blockhash,
139
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
140
+ },
141
+ 'confirmed',
142
+ ),
143
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Transaction confirmation timeout')), 60000)),
144
+ ])
145
+
146
+ const confirmationResult = confirmation as { value: { err: any } }
147
+ if (confirmationResult.value.err) {
148
+ throw new Error(`Transaction failed: ${JSON.stringify(confirmationResult.value.err)}`)
149
+ }
150
+
151
+ console.log('Transaction confirmed successfully!')
152
+ } catch (confirmError) {
153
+ console.error('Transaction confirmation failed:', confirmError)
154
+
155
+ // Check if transaction actually succeeded despite timeout
156
+ const txStatus = await connection.getSignatureStatus(signature)
157
+ if (txStatus?.value?.confirmationStatus !== 'confirmed') {
158
+ throw new Error(`Transaction was not confirmed: ${confirmError.message}`)
159
+ }
160
+ }
161
+ return {
162
+ sender: quote.quoteParams.sender,
163
+ id: signature,
164
+ sourceTxHash: signature,
165
+ adapter: this.getName(),
166
+ sourceChain: quote.quoteParams.fromChain,
167
+ targetChain: quote.quoteParams.toChain,
168
+ inputAmount: quote.quoteParams.amount,
169
+ outputAmount: quote.outputAmount.toString(),
170
+ sourceToken: quote.quoteParams.fromToken,
171
+ targetToken: quote.quoteParams.toToken,
172
+ timestamp: new Date().getTime(),
173
+ }
174
+ }
175
+
176
+ const account = walletClient.account?.address
177
+ if (!account) throw new Error('WalletClient account is not defined')
178
+ const tx = await walletClient.sendTransaction({
179
+ chain: undefined,
180
+ account,
181
+ to: quote.rawQuote.transactionRequest.to,
182
+ value: BigInt(quote.rawQuote.transactionRequest.value),
183
+ data: quote.rawQuote.transactionRequest.data,
184
+ })
185
+
186
+ return {
187
+ sender: quote.quoteParams.sender,
188
+ id: tx, // specific id for each provider
189
+ sourceTxHash: tx,
190
+ adapter: this.getName(),
191
+ sourceChain: quote.quoteParams.fromChain,
192
+ targetChain: quote.quoteParams.toChain,
193
+ inputAmount: quote.quoteParams.amount,
194
+ outputAmount: quote.outputAmount.toString(),
195
+ sourceToken: quote.quoteParams.fromToken,
196
+ targetToken: quote.quoteParams.toToken,
197
+ timestamp: new Date().getTime(),
198
+ }
199
+ }
200
+
201
+ async getTransactionStatus(p: NormalizedTxResponse): Promise<SwapStatus> {
202
+ const res = await getStatus({
203
+ fromChain: p.sourceChain === 'solana' ? 'SOL' : +p.sourceChain,
204
+ toChain: p.targetChain === 'solana' ? 'SOL' : +p.targetChain,
205
+ txHash: p.sourceTxHash,
206
+ })
207
+
208
+ return {
209
+ txHash: (res as any)?.receiving?.txHash || '',
210
+ status: res.status === 'DONE' ? 'Success' : res.status === 'FAILED' ? 'Failed' : 'Processing',
211
+ }
212
+ }
213
+ }