Skip to content

Commit 54f5f26

Browse files
committed
add support for okx
1 parent b5b02d0 commit 54f5f26

File tree

4 files changed

+100
-7
lines changed

4 files changed

+100
-7
lines changed

.env.template

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,7 @@ RPC_URL_31337=""
2727
LIFI_API_KEY=""
2828
ONEINCH_API_KEY=""
2929
PENDLE_API_KEY=""
30-
OPENOCEAN_API_KEY=""
30+
OPENOCEAN_API_KEY=""
31+
OKX_API_KEY=""
32+
OKX_PASSPHRASE=""
33+
OKX_SECRET_KEY=""

src/swapService/strategies/strategyBalmySDK.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {
1313
type Address,
1414
type Hex,
1515
encodeAbiParameters,
16+
getAddress,
1617
parseAbiParameters,
1718
parseUnits,
1819
} from "viem"
19-
import { SwapperMode } from "../interface"
20+
import { type SwapApiResponseMulticallItem, SwapperMode } from "../interface"
2021
import type { StrategyResult, SwapParams, SwapQuote } from "../types"
2122
import {
2223
SWAPPER_HANDLER_GENERIC,
@@ -26,6 +27,7 @@ import {
2627
buildApiResponseSwap,
2728
buildApiResponseVerifyDebtMax,
2829
calculateEstimatedAmountFrom,
30+
encodeApproveMulticallItem,
2931
encodeSwapMulticallItem,
3032
isExactInRepay,
3133
matchParams,
@@ -110,6 +112,11 @@ export class StrategyBalmySDK {
110112
"open-ocean": {
111113
apiKey: String(process.env.OPENOCEAN_API_KEY),
112114
},
115+
"okx-dex": {
116+
apiKey: String(process.env.OKX_API_KEY),
117+
secretKey: String(process.env.OKX_SECRET_KEY),
118+
passphrase: String(process.env.OKX_PASSPHRASE),
119+
},
113120
},
114121
},
115122
},
@@ -192,7 +199,18 @@ export class StrategyBalmySDK {
192199

193200
if (!quote) throw new Error("Quote not found")
194201

195-
const multicallItems = [
202+
const multicallItems: SwapApiResponseMulticallItem[] = []
203+
204+
if (quote.allowanceTarget) {
205+
multicallItems.push(
206+
encodeApproveMulticallItem(
207+
swapParams.tokenIn.addressInfo,
208+
quote.allowanceTarget,
209+
),
210+
)
211+
}
212+
213+
multicallItems.push(
196214
encodeSwapMulticallItem({
197215
handler: SWAPPER_HANDLER_GENERIC,
198216
mode: BigInt(SwapperMode.TARGET_DEBT),
@@ -205,7 +223,7 @@ export class StrategyBalmySDK {
205223
amountOut: swapParams.targetDebt,
206224
data: quote.data,
207225
}),
208-
]
226+
)
209227

210228
const swap = buildApiResponseSwap(swapParams.from, multicallItems)
211229

@@ -390,7 +408,6 @@ export class StrategyBalmySDK {
390408
swapParams: SwapParams,
391409
sourcesFilter?: SourcesFilter,
392410
) {
393-
// TODO type
394411
const bestQuote = await this.sdk.quoteService.getBestQuote({
395412
request: this.#getSDKQuoteFromSwapParams(swapParams, sourcesFilter),
396413
config: {
@@ -441,6 +458,7 @@ export class StrategyBalmySDK {
441458
takerAddress: swapParams.from,
442459
recipient: swapParams.receiver,
443460
filters: sourcesFilter || this.config.sourcesFilter,
461+
includeNonTransferSourcesWhenRecipientIsSet: true,
444462
}
445463
}
446464

@@ -453,6 +471,13 @@ export class StrategyBalmySDK {
453471
sdkQuote.tx.data as Hex,
454472
])
455473

474+
const sources = this.sdk.quoteService.supportedSources()
475+
const shouldTransferToReceiver =
476+
!sources[sdkQuote.source.id].supports.swapAndTransfer
477+
const allowanceTarget = sdkQuote.source.allowanceTarget
478+
? getAddress(sdkQuote.source.allowanceTarget)
479+
: undefined
480+
456481
return {
457482
swapParams,
458483
amountIn: sdkQuote.sellAmount.amount,
@@ -461,6 +486,8 @@ export class StrategyBalmySDK {
461486
amountOutMin: sdkQuote.minBuyAmount.amount,
462487
data,
463488
protocol: sdkQuote.source.name,
489+
shouldTransferToReceiver,
490+
allowanceTarget,
464491
}
465492
}
466493
}

src/swapService/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export interface SwapQuote {
3535
amountOutMin?: bigint
3636
data: Hex
3737
protocol: string
38+
shouldTransferToReceiver?: boolean
39+
allowanceTarget?: Address
3840
}
3941

4042
export interface StrategyResult {

src/swapService/utils.ts

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
encodeAbiParameters,
99
encodeFunctionData,
1010
isAddressEqual,
11+
maxUint256,
1112
parseAbiParameters,
1213
parseUnits,
1314
stringToHex,
@@ -157,8 +158,18 @@ export function buildApiResponseExactInputFromQuote(
157158
quote: SwapQuote,
158159
): SwapApiResponse {
159160
const amountOutMin = applySlippage(quote.amountOut, swapParams.slippage)
161+
const multicallItems: SwapApiResponseMulticallItem[] = []
162+
163+
if (quote.allowanceTarget) {
164+
multicallItems.push(
165+
encodeApproveMulticallItem(
166+
swapParams.tokenIn.addressInfo,
167+
quote.allowanceTarget,
168+
),
169+
)
170+
}
160171

161-
const multicallItems = [
172+
multicallItems.push(
162173
encodeSwapMulticallItem({
163174
handler: SWAPPER_HANDLER_GENERIC,
164175
mode: BigInt(SwapperMode.EXACT_IN),
@@ -171,7 +182,17 @@ export function buildApiResponseExactInputFromQuote(
171182
amountOut: 0n, // ignored in exact in
172183
data: quote.data,
173184
}),
174-
]
185+
)
186+
187+
if (quote.shouldTransferToReceiver) {
188+
multicallItems.push(
189+
encodeSweepMulticallItem(
190+
swapParams.tokenOut.addressInfo,
191+
0n,
192+
swapParams.receiver,
193+
),
194+
)
195+
}
175196

176197
const swap = buildApiResponseSwap(swapParams.from, multicallItems)
177198

@@ -324,6 +345,46 @@ export const encodeRepayAndDepositMulticallItem = (
324345
}
325346
}
326347

348+
export const encodeApproveMulticallItem = (
349+
token: Address,
350+
spender: Address,
351+
): SwapApiResponseMulticallItem => {
352+
// TODO migrate to dedicated Swapper function when available
353+
354+
const abiItem = {
355+
inputs: [
356+
{ name: "spender", type: "address" },
357+
{ name: "amount", type: "uint256" },
358+
],
359+
name: "approve",
360+
stateMutability: "nonpayable",
361+
type: "function",
362+
}
363+
364+
const functionData = encodeFunctionData({
365+
abi: [abiItem],
366+
args: [spender, maxUint256],
367+
})
368+
369+
const data = encodeAbiParameters(parseAbiParameters("address, bytes"), [
370+
token,
371+
functionData,
372+
])
373+
374+
return encodeSwapMulticallItem({
375+
handler: SWAPPER_HANDLER_GENERIC,
376+
mode: SwapperMode.EXACT_IN,
377+
account: zeroAddress,
378+
tokenIn: zeroAddress,
379+
tokenOut: zeroAddress,
380+
vaultIn: zeroAddress,
381+
accountIn: zeroAddress,
382+
receiver: zeroAddress,
383+
amountOut: 0n,
384+
data,
385+
})
386+
}
387+
327388
export const getSwapper = (chainId: number) => {
328389
const swapper = contractBook.swapper.address[chainId] || ""
329390
if (!swapper) {

0 commit comments

Comments
 (0)