@openocean.finance/widget 1.0.44 → 1.0.46

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 (47) hide show
  1. package/dist/esm/components/Header/WalletHeader.js +4 -4
  2. package/dist/esm/components/Header/WalletHeader.js.map +1 -1
  3. package/dist/esm/components/TokenList/VirtualizedTokenList.js +1 -0
  4. package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
  5. package/dist/esm/components/TransactionDetails.js +3 -0
  6. package/dist/esm/components/TransactionDetails.js.map +1 -1
  7. package/dist/esm/config/version.d.ts +1 -1
  8. package/dist/esm/config/version.js +1 -1
  9. package/dist/esm/cross/adapters/LifiAdapter.d.ts +3 -0
  10. package/dist/esm/cross/adapters/LifiAdapter.js +270 -44
  11. package/dist/esm/cross/adapters/LifiAdapter.js.map +1 -1
  12. package/dist/esm/cross/adapters/RelayAdapter.js +3 -9
  13. package/dist/esm/cross/adapters/RelayAdapter.js.map +1 -1
  14. package/dist/esm/cross/adapters/index.d.ts +1 -0
  15. package/dist/esm/cross/adapters/index.js +1 -1
  16. package/dist/esm/cross/adapters/index.js.map +1 -1
  17. package/dist/esm/cross/crossChainQuote.js +61 -2
  18. package/dist/esm/cross/crossChainQuote.js.map +1 -1
  19. package/dist/esm/cross/factory.d.ts +3 -1
  20. package/dist/esm/cross/factory.js +10 -14
  21. package/dist/esm/cross/factory.js.map +1 -1
  22. package/dist/esm/hooks/useSwapOnly.js +8 -2
  23. package/dist/esm/hooks/useSwapOnly.js.map +1 -1
  24. package/dist/esm/i18n/en.json +5 -3
  25. package/dist/esm/i18n/ja.json +3 -1
  26. package/dist/esm/i18n/zh.json +3 -1
  27. package/dist/esm/services/ExecuteRoute.d.ts +1 -0
  28. package/dist/esm/services/ExecuteRoute.js +128 -53
  29. package/dist/esm/services/ExecuteRoute.js.map +1 -1
  30. package/dist/esm/types/widget.d.ts +1 -1
  31. package/dist/esm/types/widget.js.map +1 -1
  32. package/package.json +4 -4
  33. package/src/components/Header/WalletHeader.tsx +4 -4
  34. package/src/components/TokenList/VirtualizedTokenList.tsx +15 -15
  35. package/src/components/TransactionDetails.tsx +4 -0
  36. package/src/config/version.ts +1 -1
  37. package/src/cross/adapters/LifiAdapter.ts +303 -51
  38. package/src/cross/adapters/RelayAdapter.ts +4 -12
  39. package/src/cross/adapters/index.ts +1 -1
  40. package/src/cross/crossChainQuote.ts +60 -2
  41. package/src/cross/factory.ts +12 -11
  42. package/src/hooks/useSwapOnly.ts +9 -2
  43. package/src/i18n/en.json +5 -3
  44. package/src/i18n/ja.json +3 -1
  45. package/src/i18n/zh.json +3 -1
  46. package/src/services/ExecuteRoute.ts +166 -54
  47. package/src/types/widget.ts +2 -1
@@ -2,6 +2,7 @@ import { createConfig, getQuote, getStatus } from '@lifi/sdk'
2
2
  import { WalletAdapterProps } from '@solana/wallet-adapter-base'
3
3
  import { Connection, Transaction, VersionedTransaction } from '@solana/web3.js'
4
4
  import { WalletClient, formatUnits } from 'viem'
5
+ import * as bitcoin from 'bitcoinjs-lib'
5
6
 
6
7
  import { CROSS_CHAIN_FEE_RECEIVER, ZERO_ADDRESS, Currency, SolanaToken, MAINNET_NETWORKS } from '../constants/index.js'
7
8
 
@@ -17,11 +18,25 @@ import {
17
18
  SwapStatus,
18
19
  } from './BaseSwapAdapter.js'
19
20
 
21
+ type DynamicSignPsbtParams = {
22
+ allowedSighash: number[]
23
+ unsignedPsbtBase64: string
24
+ signature: Array<{
25
+ address: string
26
+ signingIndexes: number[]
27
+ }>
28
+ }
29
+ type TransactionRequest = {
30
+ to: string
31
+ value: string
32
+ data: string
33
+ }
34
+
20
35
  export class LifiAdapter extends BaseSwapAdapter {
21
36
  constructor() {
22
37
  super()
23
38
  createConfig({
24
- integrator: 'kyberswap',
39
+ integrator: 'openocean',
25
40
  })
26
41
  }
27
42
 
@@ -32,34 +47,57 @@ export class LifiAdapter extends BaseSwapAdapter {
32
47
  return 'https://storage.googleapis.com/ks-setting-1d682dca/aed3a971-48be-4c3c-9597-5ab78073fbf11745552578218.png'
33
48
  }
34
49
  getSupportedChains(): Chain[] {
35
- return [NonEvmChain.Solana, ...MAINNET_NETWORKS]
50
+ return [NonEvmChain.Solana, NonEvmChain.Bitcoin, ...MAINNET_NETWORKS]
36
51
  }
37
52
 
38
53
  getSupportedTokens(_sourceChain: Chain, _destChain: Chain): Currency[] {
39
54
  return []
40
55
  }
41
56
 
57
+
58
+
42
59
  async getQuote(params: QuoteParams): Promise<NormalizedQuote> {
43
- const r = await getQuote({
44
- fromChain: params.fromChain === 1151111081099710 ? 'SOL' : +params.fromChain, // Arbitrum
45
- fromToken:
46
- params.fromChain === 1151111081099710
47
- ? (params.fromToken as SolanaToken).id
48
- : (params.fromToken as any).isNative
49
- ? ZERO_ADDRESS
50
- : (params.fromToken as any).wrapped.address,
60
+
61
+ let fromToken = (params.fromToken as any).isNative
62
+ ? ZERO_ADDRESS
63
+ : (params.fromToken as any).address
64
+ if (params.fromChain === 20000000000001 || params.fromChain === 1151111081099710) {
65
+ fromToken = (params.fromToken as any).address
66
+ }
67
+ let fromChain = params.fromChain === 1151111081099710 ? 'SOL' : +params.fromChain
68
+ if (params.fromChain === 20000000000001) {
69
+ fromChain = 'BTC'
70
+ }
71
+
72
+
73
+ let toToken = (params.toToken as any).isNative
74
+ ? ZERO_ADDRESS
75
+ : (params.toToken as any).address
76
+ if (params.toChain === 20000000000001 || params.toChain === 1151111081099710) {
77
+ toToken = (params.toToken as any).address
78
+ }
79
+ let toChain = params.toChain === 1151111081099710 ? 'SOL' : +params.toChain
80
+ if (params.toChain === 20000000000001) {
81
+ toChain = 'BTC'
82
+ }
83
+
84
+
85
+ let quoteParams = {
86
+ fromChain, // Arbitrum
87
+ fromToken,
51
88
  fromAmount: params.amount,
52
89
  fromAddress: params.sender === ZERO_ADDRESS ? CROSS_CHAIN_FEE_RECEIVER : params.sender,
53
-
54
- toChain: params.toChain === 1151111081099710 ? 'SOL' : +params.toChain,
55
- toToken:
56
- params.toChain === 1151111081099710
57
- ? (params.toToken as SolanaToken).id
58
- : (params.toToken as any).isNative
59
- ? ZERO_ADDRESS
60
- : (params.toToken as any).wrapped.address,
90
+ toChain,
91
+ toToken,
61
92
  toAddress: params.recipient,
62
93
  fee: params.feeBps / 10_000,
94
+ }
95
+ const r = await getQuote(quoteParams).catch(error => {
96
+ if (error && error.cause && error.cause.responseBody && error.cause.responseBody.message) {
97
+ throw new Error(error.cause.responseBody.message)
98
+ } else {
99
+ throw error
100
+ }
63
101
  })
64
102
 
65
103
  //const inputUsd = Number(r.estimate.fromAmountUSD || '0')
@@ -74,6 +112,9 @@ export class LifiAdapter extends BaseSwapAdapter {
74
112
  ? Number(r.estimate.toAmountUSD)
75
113
  : params.tokenOutUsd * +formattedOutputAmount
76
114
 
115
+ const protocolFee: any = r.estimate.feeCosts?.reduce((acc: number, curr: any) => acc + Number(curr.amountUSD), 0) || 0
116
+ const gasFeeUsd = r.estimate.gasCosts.reduce((acc: number, curr: any) => acc + Number(curr.amountUSD), 0)
117
+
77
118
  return {
78
119
  quoteParams: params,
79
120
  outputAmount: BigInt(r.estimate.toAmount),
@@ -84,13 +125,13 @@ export class LifiAdapter extends BaseSwapAdapter {
84
125
  priceImpact: !inputUsd || !outputUsd ? NaN : ((inputUsd - outputUsd) * 100) / inputUsd,
85
126
  rate: +formattedOutputAmount / +formattedInputAmount,
86
127
 
87
- gasFeeUsd: 0,
128
+ gasFeeUsd,
88
129
 
89
130
  timeEstimate: r.estimate.executionDuration,
90
131
  contractAddress: r.transactionRequest?.to || r.estimate.approvalAddress,
91
132
  rawQuote: r,
92
133
 
93
- protocolFee: 0,
134
+ protocolFee,
94
135
  platformFeePercent: (params.feeBps * 100) / 10_000,
95
136
  }
96
137
  }
@@ -103,8 +144,177 @@ export class LifiAdapter extends BaseSwapAdapter {
103
144
  sendTransaction?: WalletAdapterProps['sendTransaction'],
104
145
  connection?: Connection,
105
146
  ): Promise<NormalizedTxResponse> {
147
+ if (quote.quoteParams.fromChain === NonEvmChain.Bitcoin) {
148
+ // Get user address
149
+ const account = (walletClient as any).account?.address || quote.quoteParams.sender
150
+ if (!account) throw new Error('WalletClient account is not defined')
151
+
152
+ const transactionRequest: TransactionRequest = quote.rawQuote.transactionRequest
153
+
154
+ if (!transactionRequest.data) {
155
+ throw new Error('TransactionRequest data is missing')
156
+ }
157
+
158
+ // Parse PSBT (may be base64 or hex)
159
+ let psbt: bitcoin.Psbt
160
+ try {
161
+ // Try to parse as base64
162
+ psbt = bitcoin.Psbt.fromBase64(transactionRequest.data, { network: bitcoin.networks.bitcoin })
163
+ } catch {
164
+ try {
165
+ // Try to parse as hex
166
+ psbt = bitcoin.Psbt.fromHex(transactionRequest.data, { network: bitcoin.networks.bitcoin })
167
+ } catch (error) {
168
+ throw new Error(`Failed to parse PSBT: ${error}`)
169
+ }
170
+ }
171
+
172
+ // Detect wallet type
173
+ const anyWindow = typeof window !== 'undefined' ? (window as any) : undefined
174
+ let connectorName: string | undefined
175
+ if (anyWindow?.okxwallet?.bitcoin) connectorName = 'OKX Wallet'
176
+ else if (anyWindow?.unisat) connectorName = 'Unisat'
177
+ else if (anyWindow?.BitcoinProvider) connectorName = 'Xverse'
178
+ else if (anyWindow?.phantom?.bitcoin) connectorName = 'Phantom'
179
+ else throw new Error('No Bitcoin wallet found')
180
+
181
+ // Extract inputs to sign from PSBT
182
+ const inputsToSign: any[] = []
183
+ for (let index = 0; index < psbt.data.inputs.length; index++) {
184
+ const input = psbt.data.inputs[index]
185
+ let inputAddress: string
186
+
187
+ if (input.witnessUtxo) {
188
+ // Extract address from witnessUtxo
189
+ inputAddress = bitcoin.address.fromOutputScript(input.witnessUtxo.script, bitcoin.networks.bitcoin)
190
+ } else if (input.nonWitnessUtxo) {
191
+ // Extract address from nonWitnessUtxo (needs output index, simplified here)
192
+ // Usually needs to be extracted from transaction, using account address as default here
193
+ inputAddress = account.toString()
194
+ } else {
195
+ inputAddress = account.toString()
196
+ }
197
+
198
+ // Only add inputs that belong to the current account
199
+ if (inputAddress === account.toString()) {
200
+ inputsToSign.push({
201
+ index,
202
+ address: inputAddress,
203
+ })
204
+ }
205
+ }
206
+
207
+ if (inputsToSign.length === 0) {
208
+ throw new Error('No inputs found to sign')
209
+ }
210
+
211
+ const psbtBase64 = psbt.toBase64()
212
+ const psbtHex = psbt.toHex()
213
+ let signedPsbtBase64: string
214
+
215
+ // Sign PSBT using wallet
216
+ switch (connectorName) {
217
+ case 'OKX Wallet': {
218
+ const signOptions = {
219
+ autoFinalized: false,
220
+ toSignInputs: inputsToSign.map((item) => ({
221
+ index: item.index,
222
+ address: item.address,
223
+ sighashTypes: [1], // SIGHASH_ALL
224
+ })),
225
+ }
226
+ const response = await anyWindow.okxwallet.bitcoin.signPsbt(psbtHex, signOptions)
227
+ signedPsbtBase64 = this.convertHexToBase64(this.extractSignedPsbt(response) || '')
228
+ break
229
+ }
230
+
231
+ case 'Unisat': {
232
+ const signOptions = {
233
+ autoFinalized: false,
234
+ toSignInputs: inputsToSign.map((item) => ({
235
+ index: item.index,
236
+ address: item.address,
237
+ sighashTypes: [1],
238
+ })),
239
+ }
240
+ const response = await anyWindow.unisat.signPsbt(psbtHex, signOptions)
241
+ signedPsbtBase64 = this.convertHexToBase64(this.extractSignedPsbt(response) || '')
242
+ break
243
+ }
244
+
245
+ case 'Xverse': {
246
+ const response = await anyWindow.BitcoinProvider.request('signPsbt', {
247
+ psbt: psbtHex,
248
+ finalize: false,
249
+ toSignInputs: inputsToSign.map((item) => ({
250
+ index: item.index,
251
+ address: item.address,
252
+ })),
253
+ })
254
+ signedPsbtBase64 = this.extractSignedPsbt(response) || ''
255
+ break
256
+ }
257
+
258
+ case 'Phantom': {
259
+ const phantom = anyWindow.phantom.bitcoin
260
+ if (!phantom?.signPSBT) throw new Error('Phantom wallet does not support signPSBT')
261
+
262
+ const response = await phantom.signPSBT(psbtBase64, {
263
+ autoFinalize: false,
264
+ inputsToSign: inputsToSign.map((item) => ({
265
+ index: item.index,
266
+ address: item.address,
267
+ sighashTypes: [1],
268
+ })),
269
+ })
270
+ signedPsbtBase64 = this.extractSignedPsbt(response) || ''
271
+ break
272
+ }
273
+
274
+ default:
275
+ throw new Error(`Unsupported wallet: ${connectorName}`)
276
+ }
277
+
278
+ if (!signedPsbtBase64) {
279
+ throw new Error('Failed to sign PSBT')
280
+ }
281
+
282
+ // Finalize PSBT and extract transaction
283
+ const signedPsbt = bitcoin.Psbt.fromBase64(signedPsbtBase64, { network: bitcoin.networks.bitcoin })
284
+ signedPsbt.finalizeAllInputs()
285
+ const rawTx = signedPsbt.extractTransaction().toHex()
286
+
287
+ // Broadcast transaction to mempool.space
288
+ const txHash = await fetch('https://mempool.space/api/tx', {
289
+ method: 'POST',
290
+ headers: {
291
+ 'Content-Type': 'text/plain',
292
+ },
293
+ body: rawTx,
294
+ }).then((r) => r.text())
295
+
296
+ if (!txHash || txHash.startsWith('<')) {
297
+ throw new Error(`Failed to broadcast transaction: ${txHash}`)
298
+ }
299
+
300
+ return {
301
+ sender: quote.quoteParams.sender,
302
+ id: txHash,
303
+ sourceTxHash: txHash,
304
+ adapter: this.getName(),
305
+ sourceChain: quote.quoteParams.fromChain,
306
+ targetChain: quote.quoteParams.toChain,
307
+ inputAmount: quote.quoteParams.amount,
308
+ outputAmount: quote.outputAmount.toString(),
309
+ sourceToken: quote.quoteParams.fromToken,
310
+ targetToken: quote.quoteParams.toToken,
311
+ timestamp: new Date().getTime(),
312
+ }
313
+ }
314
+
315
+
106
316
  if (quote.quoteParams.fromChain === NonEvmChain.Solana) {
107
- if (!connection || !sendTransaction) throw new Error('Connection is not defined for Solana swap')
317
+ if (!walletClient.sendTransaction) throw new Error('Connection is not defined for Solana swap')
108
318
  const txBuffer = Buffer.from(quote.rawQuote.transactionRequest.data, 'base64')
109
319
 
110
320
  // Try to deserialize as VersionedTransaction first
@@ -125,39 +335,39 @@ export class LifiAdapter extends BaseSwapAdapter {
125
335
  console.log('Transaction parsed successfully:', transaction)
126
336
 
127
337
  // Send through wallet adapter
128
- const signature = await sendTransaction(transaction, connection)
338
+ const tx: any = await walletClient.sendTransaction(transaction)
339
+ const signature = tx.signature
340
+ // try {
341
+ // const latestBlockhash = await connection.getLatestBlockhash()
129
342
 
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
- }
343
+ // // Wait for confirmation with timeout
344
+ // const confirmation = await Promise.race([
345
+ // connection.confirmTransaction(
346
+ // {
347
+ // signature,
348
+ // blockhash: latestBlockhash.blockhash,
349
+ // lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
350
+ // },
351
+ // 'confirmed',
352
+ // ),
353
+ // new Promise((_, reject) => setTimeout(() => reject(new Error('Transaction confirmation timeout')), 60000)),
354
+ // ])
150
355
 
151
- console.log('Transaction confirmed successfully!')
152
- } catch (confirmError) {
153
- console.error('Transaction confirmation failed:', confirmError)
356
+ // const confirmationResult = confirmation as { value: { err: any } }
357
+ // if (confirmationResult.value.err) {
358
+ // throw new Error(`Transaction failed: ${JSON.stringify(confirmationResult.value.err)}`)
359
+ // }
154
360
 
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
- }
361
+ // console.log('Transaction confirmed successfully!')
362
+ // } catch (confirmError) {
363
+ // console.error('Transaction confirmation failed:', confirmError)
364
+
365
+ // // Check if transaction actually succeeded despite timeout
366
+ // const txStatus = await connection.getSignatureStatus(signature)
367
+ // if (txStatus?.value?.confirmationStatus !== 'confirmed') {
368
+ // throw new Error(`Transaction was not confirmed: ${confirmError.message}`)
369
+ // }
370
+ // }
161
371
  return {
162
372
  sender: quote.quoteParams.sender,
163
373
  id: signature,
@@ -211,4 +421,46 @@ export class LifiAdapter extends BaseSwapAdapter {
211
421
  status: res.status === 'DONE' ? 'Success' : res.status === 'FAILED' ? 'Failed' : 'Processing',
212
422
  }
213
423
  }
424
+
425
+ // Helper function: Create PSBT signature options
426
+ private createPsbtOptions(psbt: bitcoin.Psbt, request: DynamicSignPsbtParams) {
427
+ const psbtSignOptions: any = {
428
+ autoFinalized: false,
429
+ }
430
+ if (request.signature) {
431
+ const toSignInputs: any[] = []
432
+ for (const signature of request.signature) {
433
+ if (signature.signingIndexes?.length) {
434
+ for (const index of signature.signingIndexes) {
435
+ toSignInputs.push({
436
+ address: signature.address,
437
+ disableAddressValidation: (signature as any).disableAddressValidation,
438
+ index,
439
+ sighashTypes: request.allowedSighash,
440
+ })
441
+ }
442
+ }
443
+ }
444
+ psbtSignOptions.toSignInputs = toSignInputs
445
+ }
446
+ return psbtSignOptions
447
+ }
448
+
449
+ // Helper function: Convert hex to base64
450
+ private convertHexToBase64(hexString: string): string {
451
+ try {
452
+ const buffer = Buffer.from(hexString, 'hex')
453
+ return buffer.toString('base64')
454
+ } catch (error) {
455
+ // If conversion fails, it may already be base64
456
+ return hexString
457
+ }
458
+ }
459
+
460
+ // Helper function: Extract signed PSBT from wallet response
461
+ private extractSignedPsbt(response: any): string | null {
462
+ if (!response) return null
463
+ if (typeof response === 'string') return response
464
+ return response.signedPsbtHex || response.signedPsbtBase64 || response.signedPsbt || null
465
+ }
214
466
  }
@@ -25,7 +25,8 @@ import {
25
25
  sonic,
26
26
  unichain,
27
27
  zksync,
28
- celo
28
+ celo,
29
+ monad
29
30
  } from 'viem/chains'
30
31
  import type { Currency } from '../constants/index.js'
31
32
 
@@ -104,7 +105,6 @@ const plasma = defineChain({
104
105
  const SolanaChainId = 792703809
105
106
  const BitcoinChainId = 8253038
106
107
  const BitcoinAddress = 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8'
107
- const MonadChainId = 143
108
108
 
109
109
  const solanaChain = {
110
110
  id: SolanaChainId,
@@ -119,15 +119,6 @@ const bitcoinChain = {
119
119
  displayName: 'Bitcoin',
120
120
  vmType: 'bvm' as const,
121
121
  } as RelayChain
122
-
123
-
124
- const MonadChain = {
125
- id: MonadChainId,
126
- name: 'Monad',
127
- displayName: 'Monad',
128
- vmType: 'evm' as const,
129
- } as RelayChain
130
-
131
122
  export class RelayAdapter extends BaseSwapAdapter {
132
123
  constructor() {
133
124
  super()
@@ -155,9 +146,10 @@ export class RelayAdapter extends BaseSwapAdapter {
155
146
  hyperEvm,
156
147
  plasma,
157
148
  celo,
149
+ monad,
158
150
  ]
159
151
  .map(convertViemChainToRelayChain)
160
- .concat(solanaChain as any, bitcoinChain as any, MonadChain as any),
152
+ .concat(solanaChain as any, bitcoinChain as any),
161
153
  })
162
154
  }
163
155
 
@@ -5,6 +5,6 @@ export * from './RelayAdapter.js'
5
5
  export * from './MayanAdapter.js'
6
6
  // export * from './SymbiosisAdapter.js'
7
7
  // export * from './DebridgeAdapter.js'
8
- // export * from './LifiAdapter.js'
8
+ export * from './LifiAdapter.js'
9
9
  // export * from './KyberSwapAdapter.js'
10
10
  export * from './NearIntentsAdapter.js'
@@ -90,7 +90,7 @@ export async function getCrossChainQuote({
90
90
  quoteResults.push({ adapter, quote })
91
91
  }
92
92
  } catch (error) {
93
- errorMsg = error instanceof Error ? error.message : 'Unknown error'
93
+ errorMsg = error instanceof Error || error?.message ? error.message : 'Unknown error'
94
94
  // Ignore individual adapter errors, continue getting quotes from other adapters
95
95
  console.warn(`Failed to get quote from ${adapter.getName()}:`, error)
96
96
  }
@@ -148,7 +148,65 @@ export async function getCrossChainQuote({
148
148
  }
149
149
  } catch (error) {
150
150
  console.error('Error getting cross-chain quote:', error)
151
- throw error
151
+ let errors = [
152
+ {
153
+ message: 'Please connect your wallet first.',
154
+ conditions: [
155
+ 'refundTo should not be empty',
156
+ 'User is required',
157
+ 'fromAddress" is missing'
158
+ ],
159
+ },
160
+ {
161
+ message: 'The input amount is too low.',
162
+ conditions: [
163
+ 'Swap output amount is too small to cover fees required to execute swap',
164
+ 'Amount is too low for bridge',
165
+ 'Amount too small',
166
+ 'Amount too low',
167
+ ],
168
+ },
169
+ {
170
+ message: 'Insufficient balance in your wallet.',
171
+ conditions: [
172
+ 'Insufficient funds',
173
+ 'Failed to get quote',
174
+ 'Insufficient balance',
175
+ ],
176
+ },
177
+ {
178
+ message: 'Please enter valid recipient address.',
179
+ conditions: [
180
+ 'recipient should not be empty',
181
+ 'Recipient is required',
182
+ 'Invalid toAddress:'
183
+ ],
184
+ },
185
+ {
186
+ message: 'Not supported token',
187
+ conditions: [
188
+ 'not supported to token',
189
+ 'not supported from token',
190
+ 'no routes found',
191
+ 'SDK version too old for monad and solana fast mctp route'
192
+ ],
193
+ },
194
+ {
195
+ message: 'There’s no routes available for the selected token pairs',
196
+ conditions: [
197
+ 'No available quotes for the requested transfer',
198
+ ],
199
+ }
200
+ ]
201
+ if (error instanceof Error && error.message) {
202
+ const newError = errors.find(e => e.conditions.some(condition => error.message.indexOf(condition) !== -1))
203
+ if (newError) {
204
+ throw new Error(newError.message)
205
+ } else {
206
+ throw new Error(error.message)
207
+ }
208
+ }
209
+ throw new Error('Unknown error')
152
210
  }
153
211
  }
154
212
 
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  // AcrossAdapter,
5
5
  // DeBridgeAdapter,
6
- // LifiAdapter,
6
+ LifiAdapter,
7
7
  MayanAdapter,
8
8
  RelayAdapter,
9
9
  NearIntentsAdapter,
@@ -22,7 +22,7 @@ export class CrossChainSwapFactory {
22
22
  private static mayanInstance: MayanAdapter
23
23
  // private static symbiosisInstance: SymbiosisAdapter
24
24
  // private static debridgeInstance: DeBridgeAdapter
25
- // private static lifiInstance: LifiAdapter
25
+ private static lifiInstance: LifiAdapter
26
26
  // private static optimexInstance: OptimexAdapter
27
27
  // private static orbiterInstance: OrbiterAdapter
28
28
 
@@ -77,12 +77,12 @@ export class CrossChainSwapFactory {
77
77
  // return CrossChainSwapFactory.debridgeInstance
78
78
  // }
79
79
 
80
- // static getLifiInstance(): LifiAdapter {
81
- // if (!CrossChainSwapFactory.lifiInstance) {
82
- // CrossChainSwapFactory.lifiInstance = new LifiAdapter()
83
- // }
84
- // return CrossChainSwapFactory.lifiInstance
85
- // }
80
+ static getLifiInstance(): LifiAdapter {
81
+ if (!CrossChainSwapFactory.lifiInstance) {
82
+ CrossChainSwapFactory.lifiInstance = new LifiAdapter()
83
+ }
84
+ return CrossChainSwapFactory.lifiInstance
85
+ }
86
86
 
87
87
  // static getOptimexAdapter(): OptimexAdapter {
88
88
  // if (!CrossChainSwapFactory.optimexInstance) {
@@ -104,12 +104,13 @@ export class CrossChainSwapFactory {
104
104
  CrossChainSwapFactory.getMayanAdapter(),
105
105
  CrossChainSwapFactory.getRelayAdapter(),
106
106
  CrossChainSwapFactory.getNearIntentsAdapter(),
107
+ CrossChainSwapFactory.getLifiInstance(),
108
+
107
109
 
108
110
  // CrossChainSwapFactory.getAcrossAdapter(),
109
111
  // CrossChainSwapFactory.getXyFinanceAdapter(),
110
112
  // CrossChainSwapFactory.getSymbiosisAdapter(),
111
113
  // CrossChainSwapFactory.getDebridgeInstance(),
112
- // CrossChainSwapFactory.getLifiInstance(),
113
114
  // CrossChainSwapFactory.getOptimexAdapter(),
114
115
  // CrossChainSwapFactory.getOrbiterAdapter(),
115
116
  ]
@@ -132,8 +133,8 @@ export class CrossChainSwapFactory {
132
133
  // return CrossChainSwapFactory.getSymbiosisAdapter()
133
134
  // case 'debridge':
134
135
  // return CrossChainSwapFactory.getDebridgeInstance()
135
- // case 'lifi':
136
- // return CrossChainSwapFactory.getLifiInstance()
136
+ case 'lifi':
137
+ return CrossChainSwapFactory.getLifiInstance()
137
138
  // case 'optimex':
138
139
  // return CrossChainSwapFactory.getOptimexAdapter()
139
140
  // case 'orbiter':
@@ -1,6 +1,13 @@
1
1
  import { useSplitSubvariantStore } from '../stores/settings/useSplitSubvariantStore.js'
2
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
3
+
2
4
 
3
5
  export const useSwapOnly = () => {
4
- const state = useSplitSubvariantStore((state) => state.state)
5
- return state === 'swap'
6
+ const { subvariant } = useWidgetConfig()
7
+ const [state, setState] = useSplitSubvariantStore((storeState) => [storeState.state, storeState.setState])
8
+ if (subvariant === 'swap' && state !== 'swap') {
9
+ setState('swap')
10
+ return true
11
+ }
12
+ return state === 'swap' || subvariant === 'swap'
6
13
  }
package/src/i18n/en.json CHANGED
@@ -90,7 +90,7 @@
90
90
  "emptyTokenList": "We couldn't find tokens on {{chainName}} chain or you don't have any. Please search by contract address if your token doesn't appear or choose another chain.",
91
91
  "emptyTransactionHistory": "Transaction history is only stored locally and will be deleted if you clear your browser data.",
92
92
  "routeNotFound": "Reasons for that could be: low liquidity, amount selected is too low, gas costs are too high or there are no routes for the selected combination.",
93
- "toAddressIsRequired": "The destination wallet address is required to proceed with the transfer."
93
+ "toAddressIsRequired": "Please enter valid recipient address"
94
94
  },
95
95
  "title": {
96
96
  "autoRefuel": "Get {{chainName}} gas",
@@ -123,7 +123,7 @@
123
123
  "deleteTransactionHistory": "Transaction history is only stored locally and can't be recovered if you delete it.",
124
124
  "fundsLossPrevention": "Always ensure smart contract accounts are properly set up on the destination chain and avoid direct transfers to exchanges to prevent fund loss.",
125
125
  "highValueLoss": "The value of the received tokens is significantly lower than the exchanged tokens and transaction cost.",
126
- "insufficientFunds": "Insufficient balance.",
126
+ "insufficientFunds": "Insufficient balance in your wallet.",
127
127
  "insufficientGas": "You don't have enough gas to complete the transaction. You need to add at least:",
128
128
  "rateChanged": "The exchange rate has changed. By continuing the transaction, you'll accept the new rate.",
129
129
  "resetSettings": "This will reset your route priority, slippage, gas price, enabled bridges and exchanges.",
@@ -320,7 +320,9 @@
320
320
  "routePriority": "Route priority",
321
321
  "slippage": "Slippage Tolerance",
322
322
  "custom": "Custom",
323
- "resetSettings": "You're using custom settings that can affect the number or sorting of available routes."
323
+ "resetSettings": "You're using custom settings that can affect the number or sorting of available routes.",
324
+ "dynamicMode": "Dynamic Mode",
325
+ "dynamicModeTooltip": "Automatically minimizes slippage to enhance the MEV protection through running simulations."
324
326
  },
325
327
  "sendToWallet": {
326
328
  "addBookmark": "Add bookmark",
package/src/i18n/ja.json CHANGED
@@ -302,7 +302,9 @@
302
302
  "routePriority": "ルート優先度",
303
303
  "slippage": "",
304
304
  "custom": "カスタム設定",
305
- "resetSettings": "利用可能なルートの数とソートに影響する可能性があるカスタム設定を使用しています。"
305
+ "resetSettings": "利用可能なルートの数とソートに影響する可能性があるカスタム設定を使用しています。",
306
+ "dynamicMode": "動的モード",
307
+ "dynamicModeTooltip": "シミュレーションを実行することで、MEV 保護を強化するためのスリッページを自動的に最小化します。"
306
308
  },
307
309
  "sendToWallet": {
308
310
  "addBookmark": "ブックマークに追加",