@openocean.finance/widget 1.0.28 → 1.0.29

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 (110) 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 +2 -5
  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 +50 -32
  66. package/dist/esm/hooks/useRoutes.js.map +1 -1
  67. package/dist/esm/hooks/useSettingMonitor.js +1 -0
  68. package/dist/esm/hooks/useSettingMonitor.js.map +1 -1
  69. package/dist/esm/hooks/useTokenAddressBalance.d.ts +1 -1
  70. package/dist/esm/hooks/useTokenPrice.js +4 -2
  71. package/dist/esm/hooks/useTokenPrice.js.map +1 -1
  72. package/dist/esm/hooks/useTokens.d.ts +1 -1
  73. package/dist/esm/services/ExecuteRoute.js +142 -124
  74. package/dist/esm/services/ExecuteRoute.js.map +1 -1
  75. package/dist/esm/stores/form/useFieldController.d.ts +1 -1
  76. package/dist/esm/stores/routes/createRouteExecutionStore.js +6 -3
  77. package/dist/esm/stores/routes/createRouteExecutionStore.js.map +1 -1
  78. package/dist/esm/stores/routes/useSetExecutableRoute.d.ts +1 -1
  79. package/dist/esm/types/widget.d.ts +3 -0
  80. package/dist/tsconfig.tsbuildinfo +1 -0
  81. package/package.json +14 -4
  82. package/src/components/AmountInput/AmountInputEndAdornment.tsx +46 -46
  83. package/src/components/Messages/WarningMessages.tsx +7 -2
  84. package/src/components/Step/Step.tsx +37 -31
  85. package/src/components/TransactionDetails.tsx +10 -11
  86. package/src/config/version.ts +1 -1
  87. package/src/cross/adapters/AcrossAdapter.ts +193 -0
  88. package/src/cross/adapters/BaseSwapAdapter.ts +173 -0
  89. package/src/cross/adapters/DebridgeAdapter.ts +375 -0
  90. package/src/cross/adapters/LifiAdapter.ts +213 -0
  91. package/src/cross/adapters/MayanAdapter.ts +179 -0
  92. package/src/cross/adapters/NearIntentsAdapter.ts +539 -0
  93. package/src/cross/adapters/OptimexAdapter.ts +273 -0
  94. package/src/cross/adapters/OrbiterAdapter.ts +270 -0
  95. package/src/cross/adapters/RelayAdapter.ts +248 -0
  96. package/src/cross/adapters/SymbiosisAdapter.ts +144 -0
  97. package/src/cross/adapters/XYFinanceAdapter.ts +213 -0
  98. package/src/cross/adapters/index.ts +9 -0
  99. package/src/cross/constants/index.ts +223 -0
  100. package/src/cross/crossChainQuote.ts +181 -0
  101. package/src/cross/factory.ts +145 -0
  102. package/src/cross/registry.ts +65 -0
  103. package/src/hooks/useGasSufficiencyBridge.ts +1 -3
  104. package/src/hooks/useRouteExecution.ts +2 -1
  105. package/src/hooks/useRoutes.ts +64 -43
  106. package/src/hooks/useSettingMonitor.ts +1 -1
  107. package/src/hooks/useTokenPrice.ts +5 -3
  108. package/src/services/ExecuteRoute.ts +184 -171
  109. package/src/stores/routes/createRouteExecutionStore.ts +13 -4
  110. package/src/types/widget.ts +3 -0
@@ -0,0 +1,539 @@
1
+ import { OneClickService, OpenAPI, QuoteRequest } from '@defuse-protocol/one-click-sdk-typescript'
2
+ import { ChainId } from '@openocean.finance/widget-sdk'
3
+ import { Currency, SolanaToken } from '../constants/index.js'
4
+ import { useWalletSelector } from '@near-wallet-selector/react-hook'
5
+ import {
6
+ ASSOCIATED_TOKEN_PROGRAM_ID,
7
+ TOKEN_PROGRAM_ID,
8
+ createAssociatedTokenAccountInstruction,
9
+ createTransferInstruction,
10
+ getAccount,
11
+ getAssociatedTokenAddress,
12
+ } from '@solana/spl-token'
13
+ import { WalletAdapterProps } from '@solana/wallet-adapter-base'
14
+ import { Connection, PublicKey, SystemProgram, Transaction } from '@solana/web3.js'
15
+ import { WalletClient, formatUnits } from 'viem'
16
+
17
+ import { BTC_DEFAULT_RECEIVER, CROSS_CHAIN_FEE_RECEIVER, SOLANA_NATIVE, ZERO_ADDRESS } from '../constants/index.js'
18
+
19
+ import { Quote } from '../registry.js'
20
+ import {
21
+ BaseSwapAdapter,
22
+ Chain,
23
+ NearQuoteParams,
24
+ NonEvmChain,
25
+ NormalizedQuote,
26
+ NormalizedTxResponse,
27
+ SwapStatus,
28
+ } from './BaseSwapAdapter.js'
29
+
30
+ export const MappingChainIdToBlockChain: Record<string, string> = {
31
+ [NonEvmChain.Bitcoin]: 'btc',
32
+ [NonEvmChain.Solana]: 'sol',
33
+ [ChainId.MAINNET]: 'eth',
34
+ [ChainId.ARBITRUM]: 'arb',
35
+ [ChainId.BSCMAINNET]: 'bsc',
36
+ [ChainId.BERA]: 'bera',
37
+ [ChainId.MATIC]: 'pol',
38
+ [ChainId.BASE]: 'base',
39
+ }
40
+
41
+ const erc20Abi = [
42
+ {
43
+ inputs: [
44
+ { type: 'address', name: 'recipient' },
45
+ { type: 'uint256', name: 'amount' },
46
+ ],
47
+ name: 'transfer',
48
+ outputs: [{ type: 'bool', name: '' }],
49
+ stateMutability: 'nonpayable',
50
+ type: 'function',
51
+ },
52
+ ]
53
+
54
+ export class NearIntentsAdapter extends BaseSwapAdapter {
55
+ constructor() {
56
+ super()
57
+ // Initialize the API client
58
+ OpenAPI.BASE = 'https://1click.chaindefuser.com'
59
+ OpenAPI.TOKEN =
60
+ 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMjUtMDQtMjMtdjEifQ.eyJ2IjoxLCJrZXlfdHlwZSI6ImRpc3RyaWJ1dGlvbl9jaGFubmVsIiwicGFydG5lcl9pZCI6Imt5YmVyIiwiaWF0IjoxNzQ5MDQyNDk1LCJleHAiOjE3ODA1Nzg0OTV9.sC5g1Jn4BRIGXkIRmN4dnK2BzbIglLOVuOmnrTItGaAP-QU69lbyYs2QGPE-5c7dRC9Cc3s0ktO50W9VXiqQEefu-VCQTKtjsfIwfAm7wDC1XKUT7lbQL2uODqXxR6yg5d8ENu6p8F2t86_T8IEpid6b1yBidKladbs9tI2QebSp3Sn6bjtsnpD-9W2dsW0Gd6PUkpZizb--YqkmdPQ8Eu85fIxtDO64qbp0Xp6NY8caFEA1yakbwaMEUWXnNX6PB_elfH28sF0cMbqlyAGiHe98J8tZ47kga6e6yZP4UHoak3Y_eRNuX_CpwoXfULx1t8YLoSJEQuP9JsPIoyw5dA'
61
+ }
62
+
63
+ getName(): string {
64
+ return 'Near Intents'
65
+ }
66
+ getIcon(): string {
67
+ return 'https://storage.googleapis.com/ks-setting-1d682dca/000c677f-2ebc-44cc-8d76-e4c6d07627631744962669170.png'
68
+ }
69
+ getSupportedChains(): Chain[] {
70
+ return [
71
+ NonEvmChain.Solana,
72
+ NonEvmChain.Bitcoin,
73
+ NonEvmChain.Near,
74
+ ...Object.keys(MappingChainIdToBlockChain).map(Number),
75
+ ]
76
+ }
77
+
78
+ getSupportedTokens(_sourceChain: Chain, _destChain: Chain): Currency[] {
79
+ return []
80
+ }
81
+
82
+ async getQuote(params: NearQuoteParams): Promise<NormalizedQuote> {
83
+ const deadline = new Date()
84
+
85
+ // 1 hour for Bitcoin, 20 minutes for other chains
86
+ deadline.setSeconds(deadline.getSeconds() + (params.fromChain === NonEvmChain.Bitcoin ? 60 * 60 : 60 * 20))
87
+
88
+ const fromAssetId =
89
+ 'assetId' in params.fromToken
90
+ ? params.fromToken.assetId === 'near'
91
+ ? 'nep141:wrap.near'
92
+ : params.fromToken.assetId
93
+ : params.nearTokens.find(token => {
94
+ const blockchain = MappingChainIdToBlockChain[params.fromChain as ChainId]
95
+
96
+ if (params.fromChain === 'solana')
97
+ return (params.fromToken as SolanaToken).id === SOLANA_NATIVE
98
+ ? token.symbol === 'SOL' && token.blockchain === 'sol'
99
+ : token.blockchain === blockchain && token.contractAddress === (params.fromToken as any).id
100
+
101
+ return (
102
+ token.blockchain === blockchain &&
103
+ ((params.fromToken as any).isNative
104
+ ? token.symbol.toLowerCase() === params.fromToken.symbol?.toLowerCase() &&
105
+ token.assetId.includes('omft')
106
+ : token.contractAddress?.toLowerCase() === (params.fromToken as any).wrapped?.address.toLowerCase())
107
+ )
108
+ })?.assetId
109
+
110
+ const toAssetId =
111
+ 'assetId' in params.toToken
112
+ ? params.toToken.assetId === 'near'
113
+ ? 'nep141:wrap.near'
114
+ : params.toToken.assetId
115
+ : params.nearTokens.find(token => {
116
+ const blockchain = MappingChainIdToBlockChain[params.toChain as ChainId]
117
+ if (params.toChain === 'solana')
118
+ return (params.toToken as SolanaToken).id === SOLANA_NATIVE
119
+ ? token.symbol === 'SOL' && token.blockchain === 'sol'
120
+ : token.blockchain === blockchain && token.contractAddress === (params.toToken as any).id
121
+
122
+ return (
123
+ token.blockchain === blockchain &&
124
+ ((params.toToken as any).isNative
125
+ ? token.symbol.toLowerCase() === params.toToken.symbol?.toLowerCase() && token.assetId.includes('omft')
126
+ : token.contractAddress?.toLowerCase() === (params.toToken as any).wrapped?.address.toLowerCase())
127
+ )
128
+ })?.assetId
129
+
130
+ if (!fromAssetId || !toAssetId) {
131
+ throw new Error('not supported tokens')
132
+ }
133
+
134
+ // Create a quote request
135
+ const quoteRequest: QuoteRequest = {
136
+ dry: true,
137
+ deadline: deadline.toISOString(),
138
+ slippageTolerance: params.slippage,
139
+ swapType: QuoteRequest.swapType.EXACT_INPUT,
140
+
141
+ originAsset: fromAssetId,
142
+ depositType: QuoteRequest.depositType.ORIGIN_CHAIN,
143
+
144
+ destinationAsset: toAssetId,
145
+ amount: params.amount,
146
+
147
+ refundTo: params.sender,
148
+ refundType: QuoteRequest.refundType.ORIGIN_CHAIN,
149
+ referral: 'kyberswap',
150
+
151
+ recipient: params.recipient,
152
+ recipientType: QuoteRequest.recipientType.DESTINATION_CHAIN,
153
+ appFees: [
154
+ {
155
+ recipient: CROSS_CHAIN_FEE_RECEIVER.toLowerCase(),
156
+ fee: params.feeBps,
157
+ },
158
+ ],
159
+ }
160
+
161
+ const quote = await OneClickService.getQuote(quoteRequest)
162
+ const formattedInputAmount = formatUnits(BigInt(params.amount), params.fromToken.decimals)
163
+ const formattedOutputAmount = formatUnits(BigInt(quote.quote.amountOut), params.toToken.decimals)
164
+ const inputUsd = +quote.quote.amountInUsd
165
+ const outputUsd = +quote.quote.amountOutUsd
166
+
167
+ return {
168
+ quoteParams: params,
169
+ outputAmount: BigInt(quote.quote.amountOut),
170
+ formattedOutputAmount,
171
+ inputUsd: +quote.quote.amountInUsd,
172
+ outputUsd: +quote.quote.amountOutUsd,
173
+ priceImpact: !inputUsd || !outputUsd ? NaN : ((inputUsd - outputUsd) * 100) / inputUsd,
174
+ rate: +formattedOutputAmount / +formattedInputAmount,
175
+ gasFeeUsd: 0,
176
+ timeEstimate: quote.quote.timeEstimate || 0,
177
+ // Near intent dont need to approve, we send token to contract directly
178
+ contractAddress: ZERO_ADDRESS,
179
+ rawQuote: quote,
180
+ protocolFee: 0,
181
+ platformFeePercent: (params.feeBps * 100) / 10_000,
182
+ }
183
+ }
184
+
185
+ async executeSwap(
186
+ { quote }: Quote,
187
+ walletClient: WalletClient,
188
+ nearWallet?: ReturnType<typeof useWalletSelector>,
189
+ sendBtcFn?: (params: { recipient: string; amount: string | number }) => Promise<string>,
190
+ sendSolanaFn?: WalletAdapterProps['sendTransaction'],
191
+ solanaConnection?: Connection,
192
+ ): Promise<NormalizedTxResponse> {
193
+ const quoteParams = {
194
+ ...quote.rawQuote.quoteRequest,
195
+ dry: false,
196
+ // adjust slippage to 0,01% to accept the rate change
197
+ slippageTolerance:
198
+ Math.floor(quote.quoteParams.slippage * 0.9) > 1
199
+ ? Math.floor(quote.quoteParams.slippage * 0.9)
200
+ : quote.quoteParams.slippage,
201
+ }
202
+ delete quoteParams.correlationId
203
+
204
+ const refreshedQuote = await OneClickService.getQuote(quoteParams)
205
+ const depositAddress = refreshedQuote?.quote?.depositAddress
206
+
207
+ if (!depositAddress) {
208
+ throw new Error('Deposit address not found')
209
+ }
210
+
211
+ if (
212
+ refreshedQuote.quoteRequest.recipient === ZERO_ADDRESS ||
213
+ refreshedQuote.quoteRequest.refundTo === ZERO_ADDRESS ||
214
+ refreshedQuote.quoteRequest.recipient.toLowerCase() === BTC_DEFAULT_RECEIVER ||
215
+ refreshedQuote.quoteRequest.refundTo.toLowerCase() === BTC_DEFAULT_RECEIVER
216
+ ) {
217
+ throw new Error('Near Intent recipient or refundTo is ZERO ADDRESS')
218
+ }
219
+ if (BigInt(refreshedQuote.quote.minAmountOut) < BigInt(quote.rawQuote.quote.minAmountOut)) {
220
+ throw new Error('Quote amount out is less than expected')
221
+ }
222
+
223
+ const params = {
224
+ sender: quote.quoteParams.sender,
225
+ id: depositAddress, // specific id for each provider
226
+ adapter: this.getName(),
227
+ sourceChain: quote.quoteParams.fromChain,
228
+ targetChain: quote.quoteParams.toChain,
229
+ inputAmount: quote.quoteParams.amount,
230
+ outputAmount: quote.outputAmount.toString(),
231
+ sourceToken: quote.quoteParams.fromToken,
232
+ targetToken: quote.quoteParams.toToken,
233
+ timestamp: new Date().getTime(),
234
+ }
235
+
236
+ if (quote.quoteParams.fromChain === NonEvmChain.Solana) {
237
+ return new Promise<NormalizedTxResponse>(async (resolve, reject) => {
238
+ if (!sendSolanaFn || !solanaConnection) {
239
+ reject('Not connected')
240
+ return
241
+ }
242
+ const waitForConfirmation = async (txId: string) => {
243
+ try {
244
+ const latestBlockhash = await solanaConnection.getLatestBlockhash()
245
+
246
+ // Wait for confirmation with timeout
247
+ const confirmation = await Promise.race([
248
+ solanaConnection.confirmTransaction(
249
+ {
250
+ signature: txId,
251
+ blockhash: latestBlockhash.blockhash,
252
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
253
+ },
254
+ 'confirmed',
255
+ ),
256
+ new Promise((_, reject) =>
257
+ setTimeout(() => reject(new Error('Transaction confirmation timeout')), 60000),
258
+ ),
259
+ ])
260
+
261
+ const confirmationResult = confirmation as { value: { err: any } }
262
+ if (confirmationResult.value.err) {
263
+ throw new Error(`Transaction failed: ${JSON.stringify(confirmationResult.value.err)}`)
264
+ }
265
+
266
+ console.log('Transaction confirmed successfully!')
267
+ } catch (confirmError) {
268
+ console.error('Transaction confirmation failed:', confirmError)
269
+
270
+ // Check if transaction actually succeeded despite timeout
271
+ const txStatus = await solanaConnection.getSignatureStatus(txId)
272
+ if (txStatus?.value?.confirmationStatus !== 'confirmed') {
273
+ throw new Error(`Transaction was not confirmed: ${confirmError.message}`)
274
+ }
275
+ }
276
+ }
277
+
278
+ const fromPubkey = new PublicKey(quote.quoteParams.sender)
279
+ const recipientPubkey = new PublicKey(depositAddress)
280
+
281
+ const fromToken = quote.quoteParams.fromToken as SolanaToken
282
+
283
+ // const latestBlockhash = await solanaConnection.getLatestBlockhash('confirmed')
284
+
285
+ if (fromToken.id === SOLANA_NATIVE) {
286
+ const transaction = new Transaction().add(
287
+ SystemProgram.transfer({
288
+ fromPubkey: fromPubkey,
289
+ toPubkey: recipientPubkey,
290
+ lamports: BigInt(quote.quoteParams.amount),
291
+ }),
292
+ )
293
+ try {
294
+ const signature = await sendSolanaFn(transaction, solanaConnection)
295
+ await waitForConfirmation(signature)
296
+
297
+ resolve({
298
+ ...params,
299
+ sourceTxHash: signature,
300
+ })
301
+ } catch (error) {
302
+ reject(error)
303
+ }
304
+ } else {
305
+ const mintPubkey = new PublicKey(fromToken.id)
306
+ // Get associated token addresses
307
+ const senderTokenAddress = await getAssociatedTokenAddress(
308
+ mintPubkey,
309
+ fromPubkey,
310
+ false,
311
+ TOKEN_PROGRAM_ID,
312
+ ASSOCIATED_TOKEN_PROGRAM_ID,
313
+ )
314
+ const recipientTokenAddress = await getAssociatedTokenAddress(
315
+ mintPubkey,
316
+ recipientPubkey,
317
+ false,
318
+ TOKEN_PROGRAM_ID,
319
+ ASSOCIATED_TOKEN_PROGRAM_ID,
320
+ )
321
+ const transaction = new Transaction()
322
+
323
+ try {
324
+ // Check if recipient's token account exists
325
+ await getAccount(solanaConnection, recipientTokenAddress)
326
+ } catch (err) {
327
+ // Account doesn't exist, create it
328
+ console.log('Creating recipient token account...')
329
+ transaction.add(
330
+ createAssociatedTokenAccountInstruction(
331
+ fromPubkey, // payer
332
+ recipientTokenAddress, // associated token account
333
+ recipientPubkey, // owner
334
+ mintPubkey, // mint
335
+ TOKEN_PROGRAM_ID,
336
+ ASSOCIATED_TOKEN_PROGRAM_ID,
337
+ ),
338
+ )
339
+ }
340
+
341
+ // Add transfer instruction
342
+ transaction.add(
343
+ createTransferInstruction(
344
+ senderTokenAddress, // source
345
+ recipientTokenAddress, // destination
346
+ fromPubkey, // owner
347
+ BigInt(quote.quoteParams.amount),
348
+ [],
349
+ TOKEN_PROGRAM_ID,
350
+ ),
351
+ )
352
+
353
+ try {
354
+ const signature = await sendSolanaFn(transaction, solanaConnection)
355
+ await waitForConfirmation(signature)
356
+
357
+ resolve({
358
+ ...params,
359
+ sourceTxHash: signature,
360
+ })
361
+ } catch (error) {
362
+ reject(error)
363
+ }
364
+ }
365
+ return
366
+ })
367
+ }
368
+
369
+ if (quote.quoteParams.fromChain === NonEvmChain.Bitcoin) {
370
+ return new Promise<NormalizedTxResponse>(async (resolve, reject) => {
371
+ if (!sendBtcFn) {
372
+ reject('Not connected')
373
+ return
374
+ }
375
+
376
+ try {
377
+ const tx = await sendBtcFn({
378
+ recipient: depositAddress,
379
+ amount: quote.quoteParams.amount,
380
+ })
381
+ await OneClickService.submitDepositTx({
382
+ txHash: tx,
383
+ depositAddress,
384
+ }).catch(e => {
385
+ console.log('NearIntents submitDepositTx failed', e)
386
+ })
387
+ resolve({
388
+ ...params,
389
+ sourceTxHash: tx,
390
+ })
391
+ } catch (e) {
392
+ console.log(e)
393
+ reject(e)
394
+ return
395
+ }
396
+ })
397
+ }
398
+
399
+ if (quote.quoteParams.fromChain === NonEvmChain.Near) {
400
+ return new Promise<NormalizedTxResponse>(async (resolve, reject) => {
401
+ if (!nearWallet || !nearWallet.signedAccountId) {
402
+ reject('Not connected')
403
+ return
404
+ }
405
+ const isNative = (quote.quoteParams.fromToken as any).assetId === 'near'
406
+
407
+ const transactions: any = []
408
+ if (!isNative)
409
+ transactions.push({
410
+ signerId: nearWallet.signedAccountId,
411
+ receiverId: (quote.quoteParams.fromToken as any).contractAddress,
412
+ actions: [
413
+ {
414
+ type: 'FunctionCall',
415
+ params: {
416
+ methodName: 'storage_deposit',
417
+ args: { account_id: depositAddress, registration_only: true },
418
+ gas: '30000000000000',
419
+ deposit: '1250000000000000000000', // 0.00125 NEAR
420
+ },
421
+ },
422
+ ],
423
+ })
424
+
425
+ transactions.push({
426
+ signerId: nearWallet.signedAccountId,
427
+ receiverId: isNative ? depositAddress : (quote.quoteParams.fromToken as any).contractAddress,
428
+ actions: [
429
+ isNative
430
+ ? {
431
+ type: 'Transfer',
432
+ params: {
433
+ deposit: quote.quoteParams.amount,
434
+ },
435
+ }
436
+ : {
437
+ type: 'FunctionCall',
438
+ params: {
439
+ methodName: 'ft_transfer',
440
+ args: {
441
+ receiver_id: depositAddress,
442
+ amount: quote.quoteParams.amount,
443
+ },
444
+ gas: '30000000000000',
445
+ deposit: '1',
446
+ },
447
+ },
448
+ ],
449
+ })
450
+
451
+ // My near wallet is redirect to wallet website -> need store to process later
452
+ if (nearWallet?.wallet?.id === 'my-near-wallet')
453
+ localStorage.setItem(
454
+ 'cross-chain-swap-my-near-wallet-tx',
455
+ JSON.stringify({
456
+ ...params,
457
+ sourceTxHash: depositAddress,
458
+ }),
459
+ )
460
+
461
+ await nearWallet
462
+ .signAndSendTransactions({
463
+ transactions,
464
+ })
465
+ .catch(e => {
466
+ console.log('NearIntents signAndSendTransactions failed', e)
467
+ if (nearWallet?.wallet?.id === 'my-near-wallet') reject()
468
+ else reject(e)
469
+ })
470
+
471
+ resolve({
472
+ ...params,
473
+ sourceTxHash: depositAddress,
474
+ })
475
+ })
476
+ }
477
+
478
+ return new Promise<NormalizedTxResponse>(async (resolve, reject) => {
479
+ try {
480
+ if (!walletClient || !walletClient.account) reject('Not connected')
481
+ if (quote.quoteParams.sender === ZERO_ADDRESS || quote.quoteParams.recipient === ZERO_ADDRESS) {
482
+ reject('Near Intent refundTo or recipient is ZERO ADDRESS')
483
+ return
484
+ }
485
+
486
+ const account = walletClient.account?.address as `0x${string}`
487
+
488
+ const fromToken = quote.quoteParams.fromToken
489
+
490
+ const hash = await ((fromToken as any).isNative
491
+ ? walletClient.sendTransaction({
492
+ to: depositAddress as `0x${string}`,
493
+ value: BigInt(quote.quoteParams.amount),
494
+ chain: undefined,
495
+ account,
496
+ })
497
+ : walletClient.writeContract({
498
+ address: ('contractAddress' in fromToken
499
+ ? fromToken.contractAddress
500
+ : (fromToken as any).wrapped.address) as `0x${string}`,
501
+ abi: erc20Abi,
502
+ functionName: 'transfer',
503
+ args: [depositAddress, quote.quoteParams.amount],
504
+ chain: undefined,
505
+ account,
506
+ }))
507
+ await OneClickService.submitDepositTx({
508
+ txHash: hash,
509
+ depositAddress,
510
+ }).catch(e => {
511
+ console.log('NearIntents submitDepositTx failed', e)
512
+ })
513
+
514
+ resolve({
515
+ ...params,
516
+ sourceTxHash: hash,
517
+ })
518
+ } catch (e) {
519
+ reject(e)
520
+ }
521
+ })
522
+ }
523
+
524
+ async getTransactionStatus(p: NormalizedTxResponse): Promise<SwapStatus> {
525
+ const res = await OneClickService.getExecutionStatus(p.id)
526
+
527
+ return {
528
+ txHash: res.swapDetails?.destinationChainTxHashes[0]?.hash || '',
529
+ status:
530
+ res.status === 'SUCCESS'
531
+ ? 'Success'
532
+ : res.status === 'FAILED'
533
+ ? 'Failed'
534
+ : res.status === 'REFUNDED'
535
+ ? 'Refunded'
536
+ : 'Processing',
537
+ }
538
+ }
539
+ }