@openocean.finance/widget 1.0.26 → 1.0.28
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/ChainSelect/useChainSelect.d.ts +2 -1
- package/dist/esm/components/Step/StepList.d.ts +1 -1
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/hooks/useAvailableChains.d.ts +1 -1
- package/dist/esm/hooks/useChain.d.ts +1 -1
- package/dist/esm/hooks/useChains.d.ts +1 -1
- package/dist/esm/hooks/useGasRecommendation.d.ts +1 -1
- package/dist/esm/hooks/useGasRefuel.d.ts +3 -3
- package/dist/esm/hooks/useGasSufficiency.d.ts +1 -1
- package/dist/esm/hooks/useIsBatchingSupported.d.ts +1 -1
- package/dist/esm/hooks/useRouteExecution.d.ts +1 -1
- package/dist/esm/hooks/useRoutes.d.ts +3 -3
- package/dist/esm/hooks/useToAddressRequirements.d.ts +2 -2
- package/dist/esm/hooks/useTokenAddressBalance.d.ts +1 -1
- package/dist/esm/hooks/useTokenBalance.d.ts +1 -1
- package/dist/esm/hooks/useTokenBalances.d.ts +1 -1
- package/dist/esm/hooks/useTokens.d.ts +1 -1
- package/dist/esm/hooks/useTools.d.ts +2 -1
- package/dist/esm/hooks/useTransactionDetails.d.ts +2 -1
- package/dist/esm/hooks/useTransactionHistory.d.ts +1 -0
- package/dist/esm/services/ExecuteRoute.js +86 -82
- package/dist/esm/services/ExecuteRoute.js.map +1 -1
- package/dist/esm/services/OpenOceanService.d.ts +1 -0
- package/dist/esm/services/OpenOceanService.js +14 -5
- package/dist/esm/services/OpenOceanService.js.map +1 -1
- package/dist/esm/stores/form/useFieldController.d.ts +1 -1
- package/dist/esm/stores/routes/useExecutingRoutesIds.d.ts +1 -1
- package/dist/esm/stores/routes/useSetExecutableRoute.d.ts +1 -1
- package/dist/esm/stores/routes/utils.d.ts +6 -6
- package/dist/esm/utils/chainType.d.ts +5 -5
- package/package.json +1 -1
- package/src/config/version.ts +1 -1
- package/src/services/ExecuteRoute.ts +190 -180
- package/src/services/OpenOceanService.ts +14 -5
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -6,6 +6,6 @@ export declare const useFieldController: ({ name }: UseFieldControllerProps) =>
|
|
|
6
6
|
onChange: (newValue: string | number | undefined) => void;
|
|
7
7
|
onBlur: () => void;
|
|
8
8
|
name: keyof import("./types.js").DefaultValues;
|
|
9
|
-
value: string | number | ContractCall[];
|
|
9
|
+
value: string | number | import("@openocean.finance/widget-types").ContractCall[];
|
|
10
10
|
};
|
|
11
11
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useExecutingRoutesIds: () =>
|
|
1
|
+
export declare const useExecutingRoutesIds: () => string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useSetExecutableRoute: () => (route: Route, observableRouteIds?: string[]) => void;
|
|
1
|
+
export declare const useSetExecutableRoute: () => (route: import("@openocean.finance/widget-types").Route, observableRouteIds?: string[]) => void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Process, RouteExtended } from '@openocean.finance/widget-sdk';
|
|
2
|
-
export declare const isRouteDone: (route: RouteExtended) =>
|
|
3
|
-
export declare const isRoutePartiallyDone: (route: RouteExtended) =>
|
|
4
|
-
export declare const isRouteRefunded: (route: RouteExtended) =>
|
|
5
|
-
export declare const isRouteFailed: (route: RouteExtended) =>
|
|
6
|
-
export declare const isRouteActive: (route?: RouteExtended) =>
|
|
2
|
+
export declare const isRouteDone: (route: RouteExtended) => boolean;
|
|
3
|
+
export declare const isRoutePartiallyDone: (route: RouteExtended) => boolean;
|
|
4
|
+
export declare const isRouteRefunded: (route: RouteExtended) => boolean;
|
|
5
|
+
export declare const isRouteFailed: (route: RouteExtended) => boolean;
|
|
6
|
+
export declare const isRouteActive: (route?: RouteExtended) => boolean;
|
|
7
7
|
export declare const getUpdatedProcess: (currentRoute: RouteExtended, updatedRoute: RouteExtended) => Process | undefined;
|
|
8
|
-
export declare const getSourceTxHash: (route?: RouteExtended) =>
|
|
8
|
+
export declare const getSourceTxHash: (route?: RouteExtended) => string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ChainType } from '@openocean.finance/widget-sdk';
|
|
1
|
+
import { ChainId, ChainType } from '@openocean.finance/widget-sdk';
|
|
2
2
|
export declare const getChainTypeFromAddress: (address: string) => ChainType | undefined;
|
|
3
3
|
export declare const defaultChainIdsByType: {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
EVM: ChainId;
|
|
5
|
+
SVM: ChainId;
|
|
6
|
+
UTXO: ChainId;
|
|
7
|
+
MVM: ChainId;
|
|
8
8
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openocean.finance/widget",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
4
4
|
"description": "Openocean Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/index.js",
|
package/src/config/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = '@openocean.finance/widget'
|
|
2
|
-
export const version = '1.0.
|
|
2
|
+
export const version = '1.0.28'
|
|
@@ -6,116 +6,115 @@ import type {
|
|
|
6
6
|
Route,
|
|
7
7
|
} from '@openocean.finance/widget-sdk'
|
|
8
8
|
import { Connection, Transaction, VersionedTransaction } from '@solana/web3.js'
|
|
9
|
-
import
|
|
9
|
+
import { ethers } from 'ethers'
|
|
10
10
|
import { getPublicClient, getWalletClient } from 'wagmi/actions'
|
|
11
|
-
import { sendAndConfirmSolanaTransaction } from './SendAndConfirmSolanaTransaction.js'
|
|
12
11
|
import { useSettingsStore } from '../stores/settings/useSettingsStore.js'
|
|
13
|
-
import {
|
|
12
|
+
import { sendAndConfirmSolanaTransaction } from './SendAndConfirmSolanaTransaction.js'
|
|
14
13
|
|
|
15
14
|
const OpenOceanABI = [
|
|
16
15
|
{
|
|
17
|
-
|
|
16
|
+
inputs: [
|
|
17
|
+
{
|
|
18
|
+
internalType: 'contract IOpenOceanCaller',
|
|
19
|
+
name: 'caller',
|
|
20
|
+
type: 'address',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
components: [
|
|
18
24
|
{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
internalType: 'contract IERC20',
|
|
26
|
+
name: 'srcToken',
|
|
27
|
+
type: 'address',
|
|
22
28
|
},
|
|
23
29
|
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"name": "srcToken",
|
|
28
|
-
"type": "address"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"internalType": "contract IERC20",
|
|
32
|
-
"name": "dstToken",
|
|
33
|
-
"type": "address"
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"internalType": "address",
|
|
37
|
-
"name": "srcReceiver",
|
|
38
|
-
"type": "address"
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"internalType": "address",
|
|
42
|
-
"name": "dstReceiver",
|
|
43
|
-
"type": "address"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"internalType": "uint256",
|
|
47
|
-
"name": "amount",
|
|
48
|
-
"type": "uint256"
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"internalType": "uint256",
|
|
52
|
-
"name": "minReturnAmount",
|
|
53
|
-
"type": "uint256"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"internalType": "uint256",
|
|
57
|
-
"name": "guaranteedAmount",
|
|
58
|
-
"type": "uint256"
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
"internalType": "uint256",
|
|
62
|
-
"name": "flags",
|
|
63
|
-
"type": "uint256"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"internalType": "address",
|
|
67
|
-
"name": "referrer",
|
|
68
|
-
"type": "address"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"internalType": "bytes",
|
|
72
|
-
"name": "permit",
|
|
73
|
-
"type": "bytes"
|
|
74
|
-
}
|
|
75
|
-
],
|
|
76
|
-
"internalType": "struct OpenOceanExchange.SwapDescription",
|
|
77
|
-
"name": "desc",
|
|
78
|
-
"type": "tuple"
|
|
30
|
+
internalType: 'contract IERC20',
|
|
31
|
+
name: 'dstToken',
|
|
32
|
+
type: 'address',
|
|
79
33
|
},
|
|
80
34
|
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"type": "uint256"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"internalType": "uint256",
|
|
89
|
-
"name": "gasLimit",
|
|
90
|
-
"type": "uint256"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"internalType": "uint256",
|
|
94
|
-
"name": "value",
|
|
95
|
-
"type": "uint256"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"internalType": "bytes",
|
|
99
|
-
"name": "data",
|
|
100
|
-
"type": "bytes"
|
|
101
|
-
}
|
|
102
|
-
],
|
|
103
|
-
"internalType": "struct IOpenOceanCaller.CallDescription[]",
|
|
104
|
-
"name": "calls",
|
|
105
|
-
"type": "tuple[]"
|
|
106
|
-
}
|
|
107
|
-
],
|
|
108
|
-
"name": "swap",
|
|
109
|
-
"outputs": [
|
|
35
|
+
internalType: 'address',
|
|
36
|
+
name: 'srcReceiver',
|
|
37
|
+
type: 'address',
|
|
38
|
+
},
|
|
110
39
|
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
40
|
+
internalType: 'address',
|
|
41
|
+
name: 'dstReceiver',
|
|
42
|
+
type: 'address',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
internalType: 'uint256',
|
|
46
|
+
name: 'amount',
|
|
47
|
+
type: 'uint256',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
internalType: 'uint256',
|
|
51
|
+
name: 'minReturnAmount',
|
|
52
|
+
type: 'uint256',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
internalType: 'uint256',
|
|
56
|
+
name: 'guaranteedAmount',
|
|
57
|
+
type: 'uint256',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
internalType: 'uint256',
|
|
61
|
+
name: 'flags',
|
|
62
|
+
type: 'uint256',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
internalType: 'address',
|
|
66
|
+
name: 'referrer',
|
|
67
|
+
type: 'address',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
internalType: 'bytes',
|
|
71
|
+
name: 'permit',
|
|
72
|
+
type: 'bytes',
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
internalType: 'struct OpenOceanExchange.SwapDescription',
|
|
76
|
+
name: 'desc',
|
|
77
|
+
type: 'tuple',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
components: [
|
|
81
|
+
{
|
|
82
|
+
internalType: 'uint256',
|
|
83
|
+
name: 'target',
|
|
84
|
+
type: 'uint256',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
internalType: 'uint256',
|
|
88
|
+
name: 'gasLimit',
|
|
89
|
+
type: 'uint256',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
internalType: 'uint256',
|
|
93
|
+
name: 'value',
|
|
94
|
+
type: 'uint256',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
internalType: 'bytes',
|
|
98
|
+
name: 'data',
|
|
99
|
+
type: 'bytes',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
internalType: 'struct IOpenOceanCaller.CallDescription[]',
|
|
103
|
+
name: 'calls',
|
|
104
|
+
type: 'tuple[]',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
name: 'swap',
|
|
108
|
+
outputs: [
|
|
109
|
+
{
|
|
110
|
+
internalType: 'uint256',
|
|
111
|
+
name: 'returnAmount',
|
|
112
|
+
type: 'uint256',
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
stateMutability: 'payable',
|
|
116
|
+
type: 'function',
|
|
117
|
+
},
|
|
119
118
|
]
|
|
120
119
|
|
|
121
120
|
// Add helper function for handling hexadecimal conversion
|
|
@@ -147,8 +146,9 @@ interface ExtendedOpenOceanStep extends OpenOceanStep {
|
|
|
147
146
|
|
|
148
147
|
interface ExtendedRoute extends Route {
|
|
149
148
|
steps: ExtendedOpenOceanStep[]
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
prependedOperatingExpenseCost?: string
|
|
150
|
+
data?: {
|
|
151
|
+
prependedOperatingExpenseCost?: string
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -178,10 +178,12 @@ async function executeSolanaSwap(
|
|
|
178
178
|
transaction = Transaction.from(hexToUint8Array(txData))
|
|
179
179
|
}
|
|
180
180
|
} else {
|
|
181
|
-
transaction = VersionedTransaction.deserialize(
|
|
181
|
+
transaction = VersionedTransaction.deserialize(
|
|
182
|
+
hexToUint8Array(txData.slice(2))
|
|
183
|
+
)
|
|
182
184
|
|
|
183
|
-
const { blockhash } = await connection.getLatestBlockhash()
|
|
184
|
-
transaction.message.recentBlockhash = blockhash
|
|
185
|
+
const { blockhash } = await connection.getLatestBlockhash()
|
|
186
|
+
transaction.message.recentBlockhash = blockhash
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
// Check signTransaction method exists
|
|
@@ -254,7 +256,7 @@ async function executeEvmSwap(
|
|
|
254
256
|
): Promise<void> {
|
|
255
257
|
try {
|
|
256
258
|
let walletClient = await getWalletClient(options.wagmiConfig)
|
|
257
|
-
|
|
259
|
+
|
|
258
260
|
// Check if wallet is connected
|
|
259
261
|
if (!walletClient) {
|
|
260
262
|
if (options.account?.connector && options.onDisconnect) {
|
|
@@ -265,18 +267,18 @@ async function executeEvmSwap(
|
|
|
265
267
|
}
|
|
266
268
|
throw new Error('Please connect wallet first')
|
|
267
269
|
}
|
|
268
|
-
|
|
270
|
+
|
|
269
271
|
// Check if current chain matches target chain
|
|
270
272
|
const currentChainId = walletClient.chain.id
|
|
271
273
|
const targetChainId = step.action.fromChainId
|
|
272
|
-
|
|
274
|
+
|
|
273
275
|
if (currentChainId !== targetChainId) {
|
|
274
276
|
try {
|
|
275
277
|
// Try to switch to target chain
|
|
276
278
|
await walletClient.switchChain({ id: targetChainId })
|
|
277
|
-
|
|
279
|
+
|
|
278
280
|
// Get updated walletClient after chain switch
|
|
279
|
-
walletClient = await getWalletClient(options.wagmiConfig) as any
|
|
281
|
+
walletClient = (await getWalletClient(options.wagmiConfig)) as any
|
|
280
282
|
if (!walletClient || walletClient.chain.id !== targetChainId) {
|
|
281
283
|
throw new Error('Failed to switch chain')
|
|
282
284
|
}
|
|
@@ -311,7 +313,10 @@ async function executeEvmSwap(
|
|
|
311
313
|
|
|
312
314
|
// Check token approval
|
|
313
315
|
if (
|
|
314
|
-
[
|
|
316
|
+
[
|
|
317
|
+
'0x0000000000000000000000000000000000000000',
|
|
318
|
+
'0x0000000000000000000000000000000000001010',
|
|
319
|
+
].indexOf(step.action.fromToken.address) === -1
|
|
315
320
|
) {
|
|
316
321
|
let allowance = 0n
|
|
317
322
|
try {
|
|
@@ -347,7 +352,11 @@ async function executeEvmSwap(
|
|
|
347
352
|
|
|
348
353
|
const amount =
|
|
349
354
|
BigInt(step.action.fromAmount) +
|
|
350
|
-
BigInt(
|
|
355
|
+
BigInt(
|
|
356
|
+
route?.prependedOperatingExpenseCost ||
|
|
357
|
+
route?.data?.prependedOperatingExpenseCost ||
|
|
358
|
+
'0'
|
|
359
|
+
)
|
|
351
360
|
if (allowance < BigInt(amount)) {
|
|
352
361
|
const approvalAmount = options.infiniteApproval
|
|
353
362
|
? BigInt(
|
|
@@ -402,20 +411,20 @@ async function executeEvmSwap(
|
|
|
402
411
|
data: transactionRequest?.data,
|
|
403
412
|
from: walletClient.account.address,
|
|
404
413
|
to: transactionRequest?.to,
|
|
405
|
-
value: transactionRequest?.value || '0'
|
|
406
|
-
}
|
|
407
|
-
|
|
414
|
+
value: transactionRequest?.value || '0',
|
|
415
|
+
}
|
|
416
|
+
|
|
408
417
|
// 调用 swap_quote_mev 获取调整后的交易数据
|
|
409
|
-
const adjustedResponse = await swapQuoteMEV(response, { publicClient })
|
|
410
|
-
|
|
418
|
+
const adjustedResponse = await swapQuoteMEV(response, { publicClient })
|
|
419
|
+
|
|
411
420
|
// 如果 swap_quote_mev 返回了修改后的数据,更新交易请求
|
|
412
421
|
if (adjustedResponse && adjustedResponse.data !== response.data) {
|
|
413
|
-
txRequest.data = adjustedResponse.data as `0x${string}
|
|
414
|
-
txRequest.value = BigInt(adjustedResponse.value || '0')
|
|
415
|
-
console.log('Applied MEV protection with dynamic slippage')
|
|
422
|
+
txRequest.data = adjustedResponse.data as `0x${string}`
|
|
423
|
+
txRequest.value = BigInt(adjustedResponse.value || '0')
|
|
424
|
+
console.log('Applied MEV protection with dynamic slippage')
|
|
416
425
|
}
|
|
417
426
|
} catch (error) {
|
|
418
|
-
console.error('Failed to apply MEV protection:', error)
|
|
427
|
+
console.error('Failed to apply MEV protection:', error)
|
|
419
428
|
// 错误时继续使用原始交易请求
|
|
420
429
|
}
|
|
421
430
|
}
|
|
@@ -483,110 +492,111 @@ async function executeEvmSwap(
|
|
|
483
492
|
* @returns 实际金额
|
|
484
493
|
*/
|
|
485
494
|
function decimals2Amount(amount: string | number, decimals = 18): number {
|
|
486
|
-
return Number(amount) / Math.pow(10, decimals)
|
|
495
|
+
return Number(amount) / Math.pow(10, decimals)
|
|
487
496
|
}
|
|
488
497
|
|
|
489
498
|
/**
|
|
490
499
|
* 交易响应类型
|
|
491
500
|
*/
|
|
492
501
|
interface SwapResponse {
|
|
493
|
-
inAmount?: string
|
|
502
|
+
inAmount?: string
|
|
494
503
|
inToken?: {
|
|
495
|
-
decimals?: number
|
|
496
|
-
price?: string | number
|
|
497
|
-
priceUSD?: string | number
|
|
498
|
-
address?: string
|
|
499
|
-
}
|
|
500
|
-
data?: string
|
|
501
|
-
from?: string
|
|
502
|
-
to?: string
|
|
503
|
-
value?: string
|
|
504
|
-
minOutAmount?: string
|
|
504
|
+
decimals?: number
|
|
505
|
+
price?: string | number
|
|
506
|
+
priceUSD?: string | number
|
|
507
|
+
address?: string
|
|
508
|
+
}
|
|
509
|
+
data?: string
|
|
510
|
+
from?: string
|
|
511
|
+
to?: string
|
|
512
|
+
value?: string
|
|
513
|
+
minOutAmount?: string
|
|
505
514
|
}
|
|
506
515
|
|
|
507
516
|
/**
|
|
508
517
|
* 根据动态滑点调整交易参数,提供 MEV 保护
|
|
509
518
|
*/
|
|
510
519
|
async function swapQuoteMEV(
|
|
511
|
-
response: SwapResponse,
|
|
520
|
+
response: SwapResponse,
|
|
512
521
|
options?: { publicClient?: any }
|
|
513
522
|
): Promise<SwapResponse> {
|
|
514
523
|
try {
|
|
515
|
-
const inAmount = response?.inAmount
|
|
516
|
-
const inTokenDecimals = response?.inToken?.decimals || 18
|
|
517
|
-
const inTokenPrice = Number(response?.inToken?.priceUSD || 0)
|
|
518
|
-
const amount = decimals2Amount(inAmount, inTokenDecimals) * inTokenPrice
|
|
524
|
+
const inAmount = response?.inAmount
|
|
525
|
+
const inTokenDecimals = response?.inToken?.decimals || 18
|
|
526
|
+
const inTokenPrice = Number(response?.inToken?.priceUSD || 0)
|
|
527
|
+
const amount = decimals2Amount(inAmount, inTokenDecimals) * inTokenPrice
|
|
519
528
|
if (amount < 1) {
|
|
520
|
-
return response
|
|
529
|
+
return response
|
|
521
530
|
}
|
|
522
|
-
const { publicClient } = options
|
|
531
|
+
const { publicClient } = options
|
|
523
532
|
const OPENOCEAN_CONTRACT = new ethers.Contract(
|
|
524
|
-
|
|
533
|
+
'0x6352a56caadC4F1E25CD6c75970Fa768A3304e64',
|
|
525
534
|
OpenOceanABI
|
|
526
|
-
)
|
|
535
|
+
)
|
|
527
536
|
if (
|
|
528
|
-
ethers.hexlify(ethers.getBytes(response?.data ||
|
|
529
|
-
OPENOCEAN_CONTRACT.interface.getFunction(
|
|
537
|
+
ethers.hexlify(ethers.getBytes(response?.data || '0x').slice(0, 4)) !==
|
|
538
|
+
OPENOCEAN_CONTRACT.interface.getFunction('swap').selector
|
|
530
539
|
) {
|
|
531
|
-
return response
|
|
540
|
+
return response
|
|
532
541
|
}
|
|
533
|
-
|
|
534
|
-
|
|
542
|
+
const oldCallData = OPENOCEAN_CONTRACT.interface.decodeFunctionData(
|
|
543
|
+
'swap',
|
|
535
544
|
response?.data
|
|
536
|
-
)
|
|
537
|
-
|
|
538
|
-
callData[1] = [...oldCallData[1]]
|
|
539
|
-
const minOutAmount = BigInt(callData[1][5] || 0)
|
|
540
|
-
const outAmount = BigInt(callData[1][6] || 0)
|
|
541
|
-
const slippageAmount = outAmount - minOutAmount
|
|
542
|
-
|
|
543
|
-
|
|
545
|
+
)
|
|
546
|
+
const callData = [...oldCallData]
|
|
547
|
+
callData[1] = [...oldCallData[1]]
|
|
548
|
+
const minOutAmount = BigInt(callData[1][5] || 0)
|
|
549
|
+
const outAmount = BigInt(callData[1][6] || 0)
|
|
550
|
+
const slippageAmount = outAmount - minOutAmount
|
|
551
|
+
|
|
552
|
+
const minOutAmounts = await Promise.all(
|
|
544
553
|
[1, 2, 3].map(async (i) => {
|
|
545
|
-
const mockMinOutAmount =
|
|
546
|
-
|
|
554
|
+
const mockMinOutAmount =
|
|
555
|
+
minOutAmount + (slippageAmount / 4n) * BigInt(i)
|
|
556
|
+
callData[1][5] = mockMinOutAmount
|
|
547
557
|
const params = {
|
|
548
558
|
from: response?.from as `0x${string}`,
|
|
549
559
|
to: response?.to as `0x${string}`,
|
|
550
560
|
data: OPENOCEAN_CONTRACT.interface.encodeFunctionData(
|
|
551
|
-
|
|
561
|
+
'swap',
|
|
552
562
|
callData
|
|
553
563
|
) as `0x${string}`,
|
|
554
564
|
value: BigInt(response?.value || '0'),
|
|
555
|
-
}
|
|
565
|
+
}
|
|
556
566
|
try {
|
|
557
|
-
await publicClient.estimateGas(params)
|
|
558
|
-
return mockMinOutAmount
|
|
567
|
+
await publicClient.estimateGas(params)
|
|
568
|
+
return mockMinOutAmount
|
|
559
569
|
} catch (error) {
|
|
560
|
-
console.error('Failed to estimate gas:', error)
|
|
561
|
-
return undefined
|
|
570
|
+
console.error('Failed to estimate gas:', error)
|
|
571
|
+
return undefined
|
|
562
572
|
}
|
|
563
573
|
})
|
|
564
|
-
)
|
|
574
|
+
)
|
|
565
575
|
let [min1, min2] = minOutAmounts
|
|
566
576
|
.filter((value) => value !== undefined)
|
|
567
577
|
.sort((a, b) => (BigInt(b || 0) > BigInt(a || 0) ? 1 : -1))
|
|
568
|
-
.slice(0, 2)
|
|
569
|
-
min1 = min1 ?? minOutAmount
|
|
570
|
-
min2 = min2 ?? minOutAmount
|
|
571
|
-
|
|
572
|
-
const randomFactor = BigInt(Math.floor(Math.random() * 10000))
|
|
573
|
-
const minOutAmountDiff = BigInt(min1 || 0) - BigInt(min2 || 0)
|
|
574
|
-
const finalMinOutAmount =
|
|
575
|
-
(minOutAmountDiff * randomFactor / BigInt(10000)
|
|
576
|
-
|
|
578
|
+
.slice(0, 2)
|
|
579
|
+
min1 = min1 ?? minOutAmount
|
|
580
|
+
min2 = min2 ?? minOutAmount
|
|
581
|
+
|
|
582
|
+
const randomFactor = BigInt(Math.floor(Math.random() * 10000))
|
|
583
|
+
const minOutAmountDiff = BigInt(min1 || 0) - BigInt(min2 || 0)
|
|
584
|
+
const finalMinOutAmount =
|
|
585
|
+
BigInt(min2 || 0) + (minOutAmountDiff * randomFactor) / BigInt(10000)
|
|
586
|
+
|
|
577
587
|
if (finalMinOutAmount < minOutAmount) {
|
|
578
|
-
return response
|
|
588
|
+
return response
|
|
579
589
|
}
|
|
580
|
-
callData[1][5] = finalMinOutAmount
|
|
590
|
+
callData[1][5] = finalMinOutAmount
|
|
581
591
|
const finalCallData = OPENOCEAN_CONTRACT.interface.encodeFunctionData(
|
|
582
|
-
|
|
592
|
+
'swap',
|
|
583
593
|
callData
|
|
584
|
-
)
|
|
585
|
-
response.minOutAmount = finalMinOutAmount.toString()
|
|
586
|
-
response.data = finalCallData
|
|
587
|
-
return response
|
|
594
|
+
)
|
|
595
|
+
response.minOutAmount = finalMinOutAmount.toString()
|
|
596
|
+
response.data = finalCallData
|
|
597
|
+
return response
|
|
588
598
|
} catch (error) {
|
|
589
|
-
return response
|
|
599
|
+
return response
|
|
590
600
|
}
|
|
591
601
|
}
|
|
592
602
|
|
|
@@ -33,6 +33,15 @@ export class OpenOceanService {
|
|
|
33
33
|
: `${this.API_V4_URL}/${chainId}`
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
private static getSolanaAddress(chain: string, tokenAddress: string): string {
|
|
37
|
+
if (chain === '1151111081099710' && tokenAddress === 'So11111111111111111111111111111111111111112') {
|
|
38
|
+
return '11111111111111111111111111111111'
|
|
39
|
+
} else if (chain === '1151111081099710' && tokenAddress === '11111111111111111111111111111111') {
|
|
40
|
+
return 'So11111111111111111111111111111111111111112'
|
|
41
|
+
}
|
|
42
|
+
return tokenAddress
|
|
43
|
+
}
|
|
44
|
+
|
|
36
45
|
static async getQuote(params: {
|
|
37
46
|
chain: string
|
|
38
47
|
inTokenAddress: string
|
|
@@ -94,9 +103,9 @@ export class OpenOceanService {
|
|
|
94
103
|
const queryParams = new URLSearchParams({
|
|
95
104
|
quoteType: 'swap',
|
|
96
105
|
inTokenSymbol: params.inTokenSymbol,
|
|
97
|
-
inTokenAddress: params.inTokenAddress,
|
|
106
|
+
inTokenAddress: this.getSolanaAddress(params.chain, params.inTokenAddress),
|
|
98
107
|
outTokenSymbol: params.outTokenSymbol,
|
|
99
|
-
outTokenAddress: params.outTokenAddress,
|
|
108
|
+
outTokenAddress: this.getSolanaAddress(params.chain, params.outTokenAddress),
|
|
100
109
|
amountDecimals: params.amount,
|
|
101
110
|
account: params.account,
|
|
102
111
|
slippage,
|
|
@@ -105,9 +114,9 @@ export class OpenOceanService {
|
|
|
105
114
|
enabledDexIds: params.enabledDexIds || '',
|
|
106
115
|
...referrer,
|
|
107
116
|
})
|
|
108
|
-
const isV1Api = Object.keys(this.CHAIN_ID_MAP).includes(params.chain.toString())
|
|
109
|
-
const swapEndpoint = isV1Api ? 'swap-quote' : 'swap'
|
|
110
|
-
const response = await fetch(`${apiUrl}
|
|
117
|
+
// const isV1Api = Object.keys(this.CHAIN_ID_MAP).includes(params.chain.toString())
|
|
118
|
+
// const swapEndpoint = isV1Api ? 'swap-quote' : 'swap'
|
|
119
|
+
const response = await fetch(`${apiUrl}/swap?${queryParams.toString()}`)
|
|
111
120
|
return response.json()
|
|
112
121
|
}
|
|
113
122
|
|