Skip to content

Commit 07bbb29

Browse files
committed
handle dust account
1 parent 27c4421 commit 07bbb29

File tree

11 files changed

+105
-72
lines changed

11 files changed

+105
-72
lines changed

src/api/routes/swap/swapModel.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ const getSwapSchema = z.object({
255255
},
256256
example: "false",
257257
}),
258+
dustAccount: addressSchema.optional().openapi({
259+
param: {
260+
description:
261+
"Account to receive dust deposits. Defaults to `accountOut`",
262+
},
263+
example: "0x8A54C278D117854486db0F6460D901a180Fff5aa",
264+
}),
258265
routingOverride: z
259266
.string()
260267
.transform((s) => JSON.parse(s))

src/api/routes/swap/swapRouter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function parseRequest(request: Request): SwapParams {
114114

115115
return {
116116
...validatedParams,
117+
dustAccount: validatedParams.dustAccount || validatedParams.accountOut,
117118
from: getSwapper(chainId),
118119
chainId,
119120
tokenIn,

src/swapService/config/mainnet.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const mainnetRoutingConfig: ChainRoutingConfig = [
5151
strategy: StrategyERC4626Wrapper.name(),
5252
match: {
5353
tokensInOrOut: [
54+
SUSDS_MAINNET,
5455
WSTUSR_MAINNET,
5556
PT_WSTUSR1740182579,
5657
YNETH_MAINNET,

src/swapService/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface SwapApiRequest {
1616
targetDebt: bigint // ignored if not in target debt mode
1717
currentDebt: bigint // needed in exact input or output and with `isRepay` set
1818
deadline: number // timestamp in seconds
19+
dustAccount?: Address // dust will be deposited for this account or to `accountOut` if not provided
1920
routingOverride?: RoutingConfig
2021
}
2122

src/swapService/strategies/strategyBalmySDK.ts

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
getAddress,
2020
isAddress,
2121
isAddressEqual,
22+
maxUint256,
2223
parseAbiParameters,
2324
parseUnits,
2425
} from "viem"
@@ -34,7 +35,10 @@ import {
3435
buildApiResponseVerifyDebtMax,
3536
calculateEstimatedAmountFrom,
3637
encodeApproveMulticallItem,
38+
encodeDepositMulticallItem,
39+
encodeRepayMulticallItem,
3740
encodeSwapMulticallItem,
41+
encodeTargetDebtAsExactInMulticall,
3842
isExactInRepay,
3943
matchParams,
4044
promiseWithTimeout,
@@ -66,8 +70,6 @@ export type BalmyStrategyConfig = {
6670
}
6771
timeout: string
6872
sourcesFilter: SourcesFilter
69-
tryExactOut?: boolean
70-
onlyExactOut?: boolean
7173
}
7274

7375
export const defaultConfig: BalmyStrategyConfig = {
@@ -77,9 +79,6 @@ export const defaultConfig: BalmyStrategyConfig = {
7779
},
7880
timeout: DEFAULT_TIMEOUT,
7981
sourcesFilter: undefined,
80-
tryExactOut: false, // tries buy order search through balmy before falling back to binary search.
81-
// Use only if exact out behavior is known for source
82-
onlyExactOut: false, // don't try overswapping when exact out not available
8382
}
8483

8584
export class StrategyBalmySDK {
@@ -209,31 +208,13 @@ export class StrategyBalmySDK {
209208
}
210209

211210
async targetDebt(swapParams: SwapParams) {
212-
let quotes: SwapQuote[] | undefined = undefined
213-
let innerSwapParams: SwapParams
214-
if (this.config.tryExactOut && !swapParams.onlyFixedInputExactOut) {
215-
try {
216-
// into the swapper
217-
innerSwapParams = {
218-
...swapParams,
219-
receiver: swapParams.from,
220-
}
221-
const sdkQuotes = await this.#getAllQuotesWithTxs(innerSwapParams)
222-
quotes = sdkQuotes.map((q) =>
223-
this.#getSwapQuoteFromSDKQuoteWithTx(innerSwapParams, q),
224-
)
225-
} catch {}
211+
const innerSwapParams = {
212+
...swapParams,
213+
receiver: swapParams.from,
214+
swapperMode: SwapperMode.EXACT_IN,
226215
}
227216

228-
if (!quotes && !this.config.onlyExactOut) {
229-
innerSwapParams = {
230-
...swapParams,
231-
receiver: swapParams.from,
232-
swapperMode: SwapperMode.EXACT_IN,
233-
}
234-
235-
quotes = await this.#binarySearchOverswapQuote(innerSwapParams)
236-
}
217+
const quotes = await this.#binarySearchOverswapQuote(innerSwapParams)
237218

238219
if (!quotes) throw new Error("Quote not found")
239220

@@ -249,19 +230,9 @@ export class StrategyBalmySDK {
249230
)
250231
}
251232

233+
// encode as exact in swap, repay and deposit, to redirect deposit to dust account
252234
multicallItems.push(
253-
encodeSwapMulticallItem({
254-
handler: SWAPPER_HANDLER_GENERIC,
255-
mode: BigInt(SwapperMode.TARGET_DEBT),
256-
account: swapParams.accountOut,
257-
tokenIn: swapParams.tokenIn.addressInfo,
258-
tokenOut: swapParams.tokenOut.addressInfo,
259-
vaultIn: swapParams.vaultIn,
260-
accountIn: swapParams.accountIn,
261-
receiver: swapParams.receiver,
262-
amountOut: swapParams.targetDebt,
263-
data: quote.data,
264-
}),
235+
...encodeTargetDebtAsExactInMulticall(swapParams, quote.data),
265236
)
266237

267238
const swap = buildApiResponseSwap(swapParams.from, multicallItems)

src/swapService/strategies/strategyCurveLPNG.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
publicActions,
99
} from "viem"
1010
import { type SwapApiResponse, SwapperMode } from "../interface"
11-
import { runPipeline } from "../runner"
1211
import type { StrategyResult, SwapParams } from "../types"
1312
import {
1413
SWAPPER_HANDLER_GENERIC,

src/swapService/strategies/strategyERC4626Wrapper.ts

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
buildApiResponseVerifySkimMin,
2020
encodeDepositMulticallItem,
2121
encodeSwapMulticallItem,
22+
encodeTargetDebtAsExactInMulticall,
2223
findToken,
2324
isExactInRepay,
2425
matchParams,
@@ -83,13 +84,13 @@ const defaultConfig: {
8384
asset: "0xb1e25689D55734FD3ffFc939c4C3Eb52DFf8A794",
8485
assetDustEVault: "0x1E1482E7Bc32cD085d7aF61F29019Ba372B63277",
8586
},
86-
// {
87-
// chainId: 1,
88-
// protocol: "sUSDS",
89-
// vault: "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD",
90-
// asset: "0xdc035d45d973e3ec169d2276ddab16f1e407384f",
91-
// assetDustEVault: "0x98238Ee86f2c571AD06B0913bef21793dA745F57",
92-
// },
87+
{
88+
chainId: 1,
89+
protocol: "sUSDS",
90+
vault: "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD",
91+
asset: "0xdc035d45d973e3ec169d2276ddab16f1e407384f",
92+
assetDustEVault: "0x98238Ee86f2c571AD06B0913bef21793dA745F57",
93+
},
9394
],
9495
}
9596

@@ -275,7 +276,7 @@ export class StrategyERC4626Wrapper {
275276
vaultData.asset,
276277
vaultData.assetDustEVault,
277278
5n, // avoid zero shares
278-
swapParams.accountOut,
279+
swapParams.dustAccount,
279280
)
280281

281282
const multicallItems = [
@@ -484,6 +485,7 @@ export class StrategyERC4626Wrapper {
484485
...swapParams,
485486
tokenIn,
486487
vaultIn: vaultData.assetDustEVault,
488+
accountIn: swapParams.dustAccount,
487489
onlyFixedInputExactOut: true, // eliminate dust in the intermediate asset (vault underlying)
488490
}
489491

@@ -604,10 +606,12 @@ export class StrategyERC4626Wrapper {
604606
...swapParams,
605607
tokenIn,
606608
vaultIn: vaultData.assetDustEVault,
609+
accountIn: swapParams.dustAccount,
610+
mode: SwapperMode.EXACT_IN,
607611
}
608612

609613
const {
610-
swapMulticallItem: mintMulticallItem,
614+
data: mintData,
611615
amountIn: mintAmountIn,
612616
amountOut,
613617
} = await encodeMint(
@@ -617,6 +621,11 @@ export class StrategyERC4626Wrapper {
617621
swapParams.from,
618622
)
619623

624+
const mintMulticallItems = encodeTargetDebtAsExactInMulticall(
625+
mintSwapParams,
626+
mintData,
627+
)
628+
620629
const tokenOut = findToken(swapParams.chainId, vaultData.asset)
621630
if (!tokenOut) throw new Error("Inner token not found")
622631
const innerSwapParams = {
@@ -625,25 +634,16 @@ export class StrategyERC4626Wrapper {
625634
tokenOut,
626635
receiver: swapParams.from,
627636
onlyFixedInputExactOut: true, // this option will overswap, which should cover growing exchange rate
637+
encodeExactOut: true,
628638
}
629639

630640
const innerQuotes = await runPipeline(innerSwapParams)
631641

632642
return innerQuotes.map((innerQuote) => {
633-
// re-encode inner swap from target debt to exact out so that repay is not executed before mint TODO fix with exact out support in all strategies
634-
const innerSwapItems = innerQuote.swap.multicallItems.map((item) => {
635-
if (item.functionName !== "swap") return item
636-
637-
const newItem = encodeSwapMulticallItem({
638-
...item.args[0],
639-
mode: BigInt(SwapperMode.EXACT_OUT),
640-
})
641-
642-
return newItem
643-
})
644-
645-
// repay is done through mint item, which will return unused input, which is the intermediate asset
646-
const multicallItems = [...innerSwapItems, mintMulticallItem]
643+
const multicallItems = [
644+
...innerQuote.swap.multicallItems,
645+
...mintMulticallItems,
646+
]
647647

648648
const swap = buildApiResponseSwap(swapParams.from, multicallItems)
649649

@@ -872,6 +872,7 @@ export async function encodeMint(
872872
amountIn,
873873
amountOut,
874874
swapMulticallItem,
875+
data: swapData,
875876
}
876877
}
877878

src/swapService/strategies/strategyMidas.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ export class StrategyMidas {
445445
mToken.paymentToken,
446446
mToken.paymentTokenSweepVault,
447447
1n,
448-
swapParams.accountOut,
448+
swapParams.dustAccount,
449449
)
450450

451451
const multicallItems = [
@@ -547,6 +547,7 @@ export class StrategyMidas {
547547
mToken.paymentToken,
548548
) as TokenListItem,
549549
vaultIn: mToken.paymentTokenSweepVault,
550+
accountIn: swapParams.dustAccount,
550551
onlyFixedInputExactOut: true, // eliminate dust in the intermediate asset (vault underlying)
551552
}
552553

@@ -668,6 +669,7 @@ export class StrategyMidas {
668669
mToken.paymentToken,
669670
) as TokenListItem,
670671
vaultIn: mToken.paymentTokenSweepVault,
672+
accountIn: swapParams.dustAccount,
671673
}
672674
const {
673675
swapMulticallItem: depositInstantMulticallItem,

src/swapService/strategies/strategyRedirectDepositWrapper.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,11 @@ export class StrategyRedirectDepositWrapper {
9595
mode: SwapperMode.EXACT_IN,
9696
}
9797

98-
console.log()
99-
10098
const swapItem = encodeSwapMulticallItem(exactInSwapItemArgs)
10199
// if target debt is 0, encode repay(max) to repay all debt, otherwise use all of the available Swapper balance
102100
const repayAmount =
103101
swapParams.targetDebt === 0n ? maxUint256 : maxUint256 - 1n
104-
console.log(
105-
"swapParams.targetDebt === 0n: ",
106-
swapParams.targetDebt === 0n,
107-
)
102+
108103
const repayItem = encodeRepayMulticallItem(
109104
vaultData.asset,
110105
swapParams.receiver,

src/swapService/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ export interface SwapParams {
2323
slippage: number
2424
deadline: number
2525
isRepay: boolean
26+
dustAccount: Address
2627
routingOverride?: ChainRoutingConfig
2728
onlyFixedInputExactOut?: boolean // only fetch quotes where amountIn is fixed and not subject to slippage
29+
encodeExactOut?: boolean // FIXME workaround for composite repays (ERC4626 strategy / overswap)
2830
}
2931

3032
export interface SwapQuote {

0 commit comments

Comments
 (0)