@openocean.finance/widget 1.0.45 → 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.
- package/dist/esm/components/Card/InputCard.d.ts +1 -1
- package/dist/esm/components/Skeleton/WidgetSkeleton.style.d.ts +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.js +1 -0
- package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/cross/adapters/LifiAdapter.d.ts +3 -0
- package/dist/esm/cross/adapters/LifiAdapter.js +270 -44
- package/dist/esm/cross/adapters/LifiAdapter.js.map +1 -1
- package/dist/esm/cross/adapters/index.d.ts +1 -0
- package/dist/esm/cross/adapters/index.js +1 -1
- package/dist/esm/cross/adapters/index.js.map +1 -1
- package/dist/esm/cross/crossChainQuote.js +10 -4
- package/dist/esm/cross/crossChainQuote.js.map +1 -1
- package/dist/esm/cross/factory.d.ts +3 -1
- package/dist/esm/cross/factory.js +10 -14
- package/dist/esm/cross/factory.js.map +1 -1
- package/dist/esm/i18n/en.json +3 -1
- package/dist/esm/i18n/ja.json +3 -1
- package/dist/esm/i18n/zh.json +3 -1
- package/dist/esm/pages/SendToWallet/SendToWalletPage.style.d.ts +1 -1
- package/dist/esm/services/ExecuteRoute.js +1 -0
- package/dist/esm/services/ExecuteRoute.js.map +1 -1
- package/package.json +2 -2
- package/src/components/TokenList/VirtualizedTokenList.tsx +15 -15
- package/src/config/version.ts +1 -1
- package/src/cross/adapters/LifiAdapter.ts +303 -51
- package/src/cross/adapters/index.ts +1 -1
- package/src/cross/crossChainQuote.ts +10 -4
- package/src/cross/factory.ts +12 -11
- package/src/i18n/en.json +3 -1
- package/src/i18n/ja.json +3 -1
- package/src/i18n/zh.json +3 -1
- package/src/services/ExecuteRoute.ts +1 -0
|
@@ -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: '
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
338
|
+
const tx: any = await walletClient.sendTransaction(transaction)
|
|
339
|
+
const signature = tx.signature
|
|
340
|
+
// try {
|
|
341
|
+
// const latestBlockhash = await connection.getLatestBlockhash()
|
|
129
342
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
}
|
|
@@ -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
|
-
|
|
8
|
+
export * from './LifiAdapter.js'
|
|
9
9
|
// export * from './KyberSwapAdapter.js'
|
|
10
10
|
export * from './NearIntentsAdapter.js'
|
|
@@ -153,7 +153,8 @@ export async function getCrossChainQuote({
|
|
|
153
153
|
message: 'Please connect your wallet first.',
|
|
154
154
|
conditions: [
|
|
155
155
|
'refundTo should not be empty',
|
|
156
|
-
'User is required'
|
|
156
|
+
'User is required',
|
|
157
|
+
'fromAddress" is missing'
|
|
157
158
|
],
|
|
158
159
|
},
|
|
159
160
|
{
|
|
@@ -177,7 +178,8 @@ export async function getCrossChainQuote({
|
|
|
177
178
|
message: 'Please enter valid recipient address.',
|
|
178
179
|
conditions: [
|
|
179
180
|
'recipient should not be empty',
|
|
180
|
-
'Recipient is required'
|
|
181
|
+
'Recipient is required',
|
|
182
|
+
'Invalid toAddress:'
|
|
181
183
|
],
|
|
182
184
|
},
|
|
183
185
|
{
|
|
@@ -188,6 +190,12 @@ export async function getCrossChainQuote({
|
|
|
188
190
|
'no routes found',
|
|
189
191
|
'SDK version too old for monad and solana fast mctp route'
|
|
190
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
|
+
],
|
|
191
199
|
}
|
|
192
200
|
]
|
|
193
201
|
if (error instanceof Error && error.message) {
|
|
@@ -195,11 +203,9 @@ export async function getCrossChainQuote({
|
|
|
195
203
|
if (newError) {
|
|
196
204
|
throw new Error(newError.message)
|
|
197
205
|
} else {
|
|
198
|
-
debugger
|
|
199
206
|
throw new Error(error.message)
|
|
200
207
|
}
|
|
201
208
|
}
|
|
202
|
-
debugger
|
|
203
209
|
throw new Error('Unknown error')
|
|
204
210
|
}
|
|
205
211
|
}
|
package/src/cross/factory.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
// AcrossAdapter,
|
|
5
5
|
// DeBridgeAdapter,
|
|
6
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
136
|
-
|
|
136
|
+
case 'lifi':
|
|
137
|
+
return CrossChainSwapFactory.getLifiInstance()
|
|
137
138
|
// case 'optimex':
|
|
138
139
|
// return CrossChainSwapFactory.getOptimexAdapter()
|
|
139
140
|
// case 'orbiter':
|
package/src/i18n/en.json
CHANGED
|
@@ -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": "ブックマークに追加",
|
package/src/i18n/zh.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": "添加到收藏",
|