@strkfarm/sdk 2.0.0-dev.3 → 2.0.0-dev.5
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/index.browser.global.js +395 -159
- package/dist/index.browser.mjs +395 -159
- package/dist/index.js +395 -159
- package/dist/index.mjs +395 -159
- package/package.json +1 -1
- package/src/strategies/universal-adapters/extended-adapter.ts +1 -0
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +775 -395
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +4 -4
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +1 -1
|
@@ -1,15 +1,43 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
2
|
import { IConfig, Protocols, TokenInfo } from "@/interfaces";
|
|
3
3
|
import { PricerBase } from "@/modules/pricerBase";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
BaseAdapter,
|
|
6
|
+
BaseAdapterConfig,
|
|
7
|
+
SupportedPosition,
|
|
8
|
+
PositionInfo,
|
|
9
|
+
PositionAPY,
|
|
10
|
+
APYType,
|
|
11
|
+
ManageCall,
|
|
12
|
+
AdapterLeafType,
|
|
13
|
+
GenerateCallFn,
|
|
14
|
+
DepositParams,
|
|
15
|
+
WithdrawParams,
|
|
16
|
+
PositionAmount,
|
|
17
|
+
} from "./baseAdapter";
|
|
18
|
+
import {
|
|
19
|
+
SIMPLE_SANITIZER,
|
|
20
|
+
SIMPLE_SANITIZER_V2,
|
|
21
|
+
toBigInt,
|
|
22
|
+
VESU_SINGLETON,
|
|
23
|
+
VESU_V2_MODIFY_POSITION_SANITIZER,
|
|
24
|
+
} from "./adapter-utils";
|
|
6
25
|
import { hash, uint256, Contract, CairoCustomEnum, num } from "starknet";
|
|
7
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
VesuAdapter,
|
|
28
|
+
VesuMultiplyCallParams,
|
|
29
|
+
VesuModifyDelegationCallParams,
|
|
30
|
+
getVesuSingletonAddress,
|
|
31
|
+
VesuPools,
|
|
32
|
+
Swap,
|
|
33
|
+
IncreaseLeverParams,
|
|
34
|
+
DecreaseLeverParams,
|
|
35
|
+
} from "./vesu-adapter";
|
|
8
36
|
import { logger } from "@/utils";
|
|
9
37
|
import { WALLET_ADDRESS } from "../vesu-extended-strategy/utils/constants";
|
|
10
|
-
import VesuMultiplyAbi from
|
|
11
|
-
import VesuSingletonAbi from
|
|
12
|
-
import VesuPoolV2Abi from
|
|
38
|
+
import VesuMultiplyAbi from "@/data/vesu-multiple.abi.json";
|
|
39
|
+
import VesuSingletonAbi from "../../data/vesu-singleton.abi.json";
|
|
40
|
+
import VesuPoolV2Abi from "@/data/vesu-pool-v2.abi.json";
|
|
13
41
|
import { EkuboQuoter, TokenMarketData } from "@/modules";
|
|
14
42
|
import { calculateDebtReductionAmountForWithdrawal } from "../vesu-extended-strategy/utils/helper";
|
|
15
43
|
import { HealthFactorMath } from "@/utils/health-factor-math";
|
|
@@ -24,7 +52,10 @@ export interface VesuMultiplyAdapterConfig extends BaseAdapterConfig {
|
|
|
24
52
|
quoteAmountToFetchPrice: Web3Number;
|
|
25
53
|
}
|
|
26
54
|
|
|
27
|
-
export class VesuMultiplyAdapter extends BaseAdapter<
|
|
55
|
+
export class VesuMultiplyAdapter extends BaseAdapter<
|
|
56
|
+
DepositParams,
|
|
57
|
+
WithdrawParams
|
|
58
|
+
> {
|
|
28
59
|
readonly config: VesuMultiplyAdapterConfig;
|
|
29
60
|
readonly vesuAdapter: VesuAdapter;
|
|
30
61
|
readonly tokenMarketData: TokenMarketData;
|
|
@@ -37,15 +68,27 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
37
68
|
collateral: config.collateral,
|
|
38
69
|
debt: config.debt,
|
|
39
70
|
vaultAllocator: config.vaultAllocator,
|
|
40
|
-
id:
|
|
71
|
+
id: "",
|
|
41
72
|
});
|
|
42
|
-
this.tokenMarketData = new TokenMarketData(
|
|
73
|
+
this.tokenMarketData = new TokenMarketData(
|
|
74
|
+
this.config.pricer,
|
|
75
|
+
this.config.networkConfig
|
|
76
|
+
);
|
|
43
77
|
}
|
|
44
78
|
|
|
45
|
-
protected async getAPY(
|
|
79
|
+
protected async getAPY(
|
|
80
|
+
supportedPosition: SupportedPosition
|
|
81
|
+
): Promise<PositionAPY> {
|
|
46
82
|
const CACHE_KEY = `apy_${this.config.poolId.address}_${supportedPosition.asset.symbol}`;
|
|
47
83
|
const cacheData = this.getCache<PositionAPY>(CACHE_KEY);
|
|
48
|
-
console.log(
|
|
84
|
+
console.log(
|
|
85
|
+
`${VesuMultiplyAdapter.name}::getAPY cacheData: ${JSON.stringify(
|
|
86
|
+
cacheData
|
|
87
|
+
)}`,
|
|
88
|
+
this.vesuAdapter.config.poolId.shortString(),
|
|
89
|
+
this.vesuAdapter.config.collateral.symbol,
|
|
90
|
+
this.vesuAdapter.config.debt.symbol
|
|
91
|
+
);
|
|
49
92
|
if (cacheData) {
|
|
50
93
|
return cacheData;
|
|
51
94
|
}
|
|
@@ -53,24 +96,30 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
53
96
|
// Get Vesu pools to find APY for the asset
|
|
54
97
|
const allVesuPools = await VesuAdapter.getVesuPools();
|
|
55
98
|
const asset = supportedPosition.asset;
|
|
56
|
-
const pool = allVesuPools.pools.find(p =>
|
|
99
|
+
const pool = allVesuPools.pools.find((p) =>
|
|
100
|
+
this.vesuAdapter.config.poolId.eqString(num.getHexString(p.id))
|
|
101
|
+
);
|
|
57
102
|
if (!pool) {
|
|
58
|
-
logger.warn(
|
|
103
|
+
logger.warn(
|
|
104
|
+
`VesuMultiplyAdapter: Pool not found for token ${asset.symbol}`
|
|
105
|
+
);
|
|
59
106
|
return {
|
|
60
107
|
apy: 0,
|
|
61
|
-
type: APYType.BASE
|
|
108
|
+
type: APYType.BASE,
|
|
62
109
|
};
|
|
63
110
|
}
|
|
64
111
|
// Find the asset stats for our token
|
|
65
|
-
const assetStats = pool.assets.find(
|
|
66
|
-
a.symbol.toLowerCase() === asset.symbol.toLowerCase()
|
|
112
|
+
const assetStats = pool.assets.find(
|
|
113
|
+
(a: any) => a.symbol.toLowerCase() === asset.symbol.toLowerCase()
|
|
67
114
|
)?.stats;
|
|
68
115
|
|
|
69
116
|
if (!assetStats) {
|
|
70
|
-
logger.warn(
|
|
117
|
+
logger.warn(
|
|
118
|
+
`VesuMultiplyAdapter: Asset stats not found for token ${asset.symbol}`
|
|
119
|
+
);
|
|
71
120
|
return {
|
|
72
121
|
apy: 0,
|
|
73
|
-
type: APYType.BASE
|
|
122
|
+
type: APYType.BASE,
|
|
74
123
|
};
|
|
75
124
|
}
|
|
76
125
|
// Get appropriate APY based on position type
|
|
@@ -79,15 +128,21 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
79
128
|
// For debt positions, use borrow APY
|
|
80
129
|
apy = Number(assetStats.borrowApr?.value || 0) / 1e18;
|
|
81
130
|
|
|
82
|
-
// todo
|
|
131
|
+
// todo
|
|
83
132
|
// Account for rewards on debt token
|
|
84
133
|
} else {
|
|
85
134
|
// For collateral positions, use supply APY
|
|
86
135
|
const isAssetBTC = asset.symbol.toLowerCase().includes("btc");
|
|
87
|
-
const baseAPY =
|
|
136
|
+
const baseAPY =
|
|
137
|
+
Number(
|
|
138
|
+
isAssetBTC
|
|
139
|
+
? assetStats.btcFiSupplyApr?.value + assetStats.supplyApy?.value
|
|
140
|
+
: assetStats.supplyApy?.value || 0
|
|
141
|
+
) / 1e18;
|
|
88
142
|
|
|
89
143
|
// account for reward yield (like STRK rewards)
|
|
90
|
-
const rewardAPY =
|
|
144
|
+
const rewardAPY =
|
|
145
|
+
Number(assetStats.defiSpringSupplyApr?.value || "0") / 1e18;
|
|
91
146
|
|
|
92
147
|
// account for base yield of LST
|
|
93
148
|
const isSupported = this.tokenMarketData.isAPYSupported(asset);
|
|
@@ -99,13 +154,16 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
99
154
|
}
|
|
100
155
|
const result = {
|
|
101
156
|
apy,
|
|
102
|
-
type: supportedPosition.isDebt ? APYType.BASE : APYType.BASE
|
|
157
|
+
type: supportedPosition.isDebt ? APYType.BASE : APYType.BASE,
|
|
103
158
|
};
|
|
104
159
|
|
|
105
160
|
this.setCache(CACHE_KEY, result, 300000); // Cache for 5 minutes
|
|
106
161
|
return result;
|
|
107
162
|
} catch (error) {
|
|
108
|
-
logger.error(
|
|
163
|
+
logger.error(
|
|
164
|
+
`VesuMultiplyAdapter: Error getting APY for ${supportedPosition.asset.symbol}:`,
|
|
165
|
+
error
|
|
166
|
+
);
|
|
109
167
|
// return {
|
|
110
168
|
// apy: 0,
|
|
111
169
|
// type: APYType.BASE
|
|
@@ -114,7 +172,9 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
114
172
|
}
|
|
115
173
|
}
|
|
116
174
|
|
|
117
|
-
protected async getPosition(
|
|
175
|
+
protected async getPosition(
|
|
176
|
+
supportedPosition: SupportedPosition
|
|
177
|
+
): Promise<PositionAmount> {
|
|
118
178
|
const CACHE_KEY = `position_${this.config.poolId.address}_${supportedPosition.asset.symbol}`;
|
|
119
179
|
const cacheData = this.getCache<PositionAmount>(CACHE_KEY);
|
|
120
180
|
if (cacheData) {
|
|
@@ -125,19 +185,23 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
125
185
|
// Use VesuAdapter to get positions
|
|
126
186
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
127
187
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
128
|
-
|
|
129
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
130
|
-
|
|
188
|
+
|
|
189
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
190
|
+
this.config.networkConfig
|
|
191
|
+
);
|
|
192
|
+
|
|
131
193
|
// Find the position for our asset
|
|
132
|
-
let position = positions.find(p =>
|
|
194
|
+
let position = positions.find((p) =>
|
|
133
195
|
p.token.address.eq(supportedPosition.asset.address)
|
|
134
196
|
);
|
|
135
197
|
|
|
136
198
|
if (!position) {
|
|
137
|
-
logger.warn(
|
|
199
|
+
logger.warn(
|
|
200
|
+
`VesuMultiplyAdapter: Position not found for token ${supportedPosition.asset.symbol}`
|
|
201
|
+
);
|
|
138
202
|
return {
|
|
139
|
-
amount: new Web3Number(
|
|
140
|
-
remarks: "Position not found"
|
|
203
|
+
amount: new Web3Number("0", supportedPosition.asset.decimals),
|
|
204
|
+
remarks: "Position not found",
|
|
141
205
|
};
|
|
142
206
|
}
|
|
143
207
|
|
|
@@ -149,7 +213,10 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
149
213
|
this.setCache(CACHE_KEY, position, 60000); // Cache for 1 minute
|
|
150
214
|
return position;
|
|
151
215
|
} catch (error) {
|
|
152
|
-
logger.error(
|
|
216
|
+
logger.error(
|
|
217
|
+
`VesuMultiplyAdapter: Error getting position for ${supportedPosition.asset.symbol}:`,
|
|
218
|
+
error
|
|
219
|
+
);
|
|
153
220
|
// return new Web3Number('0', supportedPosition.asset.decimals);
|
|
154
221
|
throw error;
|
|
155
222
|
}
|
|
@@ -157,7 +224,10 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
157
224
|
|
|
158
225
|
async maxBorrowableAPY(): Promise<number> {
|
|
159
226
|
// get collateral APY
|
|
160
|
-
const collateralAPY = await this.getAPY({
|
|
227
|
+
const collateralAPY = await this.getAPY({
|
|
228
|
+
asset: this.config.collateral,
|
|
229
|
+
isDebt: false,
|
|
230
|
+
});
|
|
161
231
|
const apy = collateralAPY.apy * 0.8;
|
|
162
232
|
return apy;
|
|
163
233
|
}
|
|
@@ -170,58 +240,92 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
170
240
|
// Get current positions
|
|
171
241
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
172
242
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
173
|
-
|
|
174
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
175
|
-
|
|
176
|
-
|
|
243
|
+
|
|
244
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
245
|
+
this.config.networkConfig
|
|
246
|
+
);
|
|
247
|
+
const collateralPosition = positions.find((p) =>
|
|
248
|
+
p.token.address.eq(collateral.address)
|
|
249
|
+
);
|
|
250
|
+
const debtPosition = positions.find((p) =>
|
|
251
|
+
p.token.address.eq(debt.address)
|
|
252
|
+
);
|
|
177
253
|
|
|
178
254
|
if (!collateralPosition || !debtPosition) {
|
|
179
|
-
throw new Error(
|
|
255
|
+
throw new Error("Could not find current positions");
|
|
180
256
|
}
|
|
181
257
|
|
|
182
258
|
// Calculate max borrowable amount
|
|
183
259
|
const maxBorrowableAPY = await this.maxBorrowableAPY();
|
|
184
|
-
const maxBorrowable =
|
|
185
|
-
this.
|
|
186
|
-
|
|
187
|
-
|
|
260
|
+
const maxBorrowable =
|
|
261
|
+
await this.vesuAdapter.getMaxBorrowableByInterestRate(
|
|
262
|
+
this.config.networkConfig,
|
|
263
|
+
debt,
|
|
264
|
+
maxBorrowableAPY
|
|
265
|
+
);
|
|
266
|
+
logger.verbose(
|
|
267
|
+
`VesuMultiplyAdapter: Max borrowable: ${maxBorrowable.toNumber()}`
|
|
268
|
+
);
|
|
269
|
+
const debtCap = await this.vesuAdapter.getDebtCap(
|
|
270
|
+
this.config.networkConfig
|
|
188
271
|
);
|
|
189
|
-
logger.verbose(`VesuMultiplyAdapter: Max borrowable: ${maxBorrowable.toNumber()}`);
|
|
190
|
-
const debtCap = await this.vesuAdapter.getDebtCap(this.config.networkConfig);
|
|
191
272
|
logger.verbose(`VesuMultiplyAdapter: Debt cap: ${debtCap.toNumber()}`);
|
|
192
273
|
const actualMaxBorrowable = maxBorrowable.minimum(debtCap);
|
|
193
|
-
logger.verbose(
|
|
274
|
+
logger.verbose(
|
|
275
|
+
`VesuMultiplyAdapter: Actual max borrowable: ${actualMaxBorrowable.toNumber()}`
|
|
276
|
+
);
|
|
194
277
|
|
|
195
278
|
// Calculate max collateral that can be deposited based on LTV
|
|
196
|
-
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
197
|
-
|
|
279
|
+
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
280
|
+
this.config.networkConfig
|
|
281
|
+
);
|
|
282
|
+
const collateralPrice = await this.config.pricer.getPrice(
|
|
283
|
+
collateral.symbol
|
|
284
|
+
);
|
|
198
285
|
if (collateralPrice.price === 0) {
|
|
199
|
-
throw new Error(
|
|
286
|
+
throw new Error("Collateral price is 0");
|
|
200
287
|
}
|
|
201
288
|
const debtPrice = await this.config.pricer.getPrice(debt.symbol);
|
|
202
289
|
if (debtPrice.price === 0) {
|
|
203
|
-
throw new Error(
|
|
290
|
+
throw new Error("Debt price is 0");
|
|
204
291
|
}
|
|
205
|
-
const maxCollateralFromDebt =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
292
|
+
const maxCollateralFromDebt =
|
|
293
|
+
HealthFactorMath.getMinCollateralRequiredOnLooping(
|
|
294
|
+
actualMaxBorrowable,
|
|
295
|
+
debtPrice.price,
|
|
296
|
+
this.config.targetHealthFactor,
|
|
297
|
+
maxLTV,
|
|
298
|
+
collateralPrice.price,
|
|
299
|
+
collateral
|
|
300
|
+
);
|
|
213
301
|
|
|
214
|
-
const maxDepositAmount = amount
|
|
302
|
+
const maxDepositAmount = amount
|
|
303
|
+
? amount.minimum(maxCollateralFromDebt)
|
|
304
|
+
: maxCollateralFromDebt;
|
|
215
305
|
const usdValue = await this.getUSDValue(collateral, maxDepositAmount);
|
|
216
|
-
logger.verbose(
|
|
217
|
-
|
|
218
|
-
|
|
306
|
+
logger.verbose(
|
|
307
|
+
`VesuMultiplyAdapter: Max deposit::USD value: ${usdValue}, amount: ${maxDepositAmount.toNumber()}`
|
|
308
|
+
);
|
|
309
|
+
const apys = await Promise.all([
|
|
310
|
+
this.getAPY({ asset: collateral, isDebt: false }),
|
|
311
|
+
this.getAPY({ asset: debt, isDebt: true }),
|
|
312
|
+
]);
|
|
313
|
+
logger.verbose(
|
|
314
|
+
`VesuMultiplyAdapter: Apys: ${apys[0].apy}, ${apys[1].apy}`
|
|
315
|
+
);
|
|
219
316
|
|
|
220
317
|
const borrowAmountUSD = actualMaxBorrowable.multipliedBy(debtPrice.price);
|
|
221
|
-
logger.verbose(
|
|
318
|
+
logger.verbose(
|
|
319
|
+
`VesuMultiplyAdapter: Borrow amount: ${actualMaxBorrowable.toNumber()}, borrow amount USD: ${borrowAmountUSD.toNumber()}`
|
|
320
|
+
);
|
|
222
321
|
const netCollateralUSD = usdValue + borrowAmountUSD.toNumber();
|
|
223
|
-
const netAPY =
|
|
224
|
-
|
|
322
|
+
const netAPY =
|
|
323
|
+
(apys[0].apy * netCollateralUSD +
|
|
324
|
+
apys[1].apy * borrowAmountUSD.toNumber()) /
|
|
325
|
+
usdValue;
|
|
326
|
+
logger.verbose(
|
|
327
|
+
`VesuMultiplyAdapter: Max deposit amount: ${maxDepositAmount.toNumber()}, netAPY: ${netAPY}`
|
|
328
|
+
);
|
|
225
329
|
return {
|
|
226
330
|
tokenInfo: collateral,
|
|
227
331
|
amount: maxDepositAmount,
|
|
@@ -229,12 +333,15 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
229
333
|
remarks: "Max deposit based on available debt capacity",
|
|
230
334
|
apy: {
|
|
231
335
|
apy: netAPY,
|
|
232
|
-
type: APYType.BASE
|
|
336
|
+
type: APYType.BASE,
|
|
233
337
|
},
|
|
234
|
-
protocol: this.protocol
|
|
338
|
+
protocol: this.protocol,
|
|
235
339
|
};
|
|
236
340
|
} catch (error) {
|
|
237
|
-
logger.error(
|
|
341
|
+
logger.error(
|
|
342
|
+
`VesuMultiplyAdapter: Error calculating max deposit:`,
|
|
343
|
+
error
|
|
344
|
+
);
|
|
238
345
|
throw error;
|
|
239
346
|
}
|
|
240
347
|
}
|
|
@@ -247,28 +354,50 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
247
354
|
// Calculate how much can be withdrawn without affecting health factor too much
|
|
248
355
|
this.vesuAdapter.networkConfig = this.config.networkConfig;
|
|
249
356
|
this.vesuAdapter.pricer = this.config.pricer;
|
|
250
|
-
|
|
251
|
-
const positions = await this.vesuAdapter.getPositions(
|
|
252
|
-
|
|
253
|
-
|
|
357
|
+
|
|
358
|
+
const positions = await this.vesuAdapter.getPositions(
|
|
359
|
+
this.config.networkConfig
|
|
360
|
+
);
|
|
361
|
+
const collateralPosition = positions.find((p) =>
|
|
362
|
+
p.token.address.eq(collateral.address)
|
|
363
|
+
);
|
|
364
|
+
const debtPosition = positions.find((p) =>
|
|
365
|
+
p.token.address.eq(this.config.debt.address)
|
|
366
|
+
);
|
|
254
367
|
|
|
255
368
|
if (!collateralPosition || !debtPosition) {
|
|
256
|
-
throw new Error(
|
|
369
|
+
throw new Error("Could not find current positions");
|
|
257
370
|
}
|
|
258
371
|
|
|
259
372
|
// Calculate max withdrawable (conservative approach)
|
|
260
|
-
const collateralPrice =
|
|
373
|
+
const collateralPrice =
|
|
374
|
+
collateralPosition.usdValue / collateralPosition.amount.toNumber();
|
|
261
375
|
const debtInCollateral = debtPosition.usdValue / collateralPrice;
|
|
262
376
|
const maxWithdrawable = collateralPosition.amount.minus(debtInCollateral);
|
|
263
377
|
|
|
264
|
-
const result = maxWithdrawable.greaterThan(0)
|
|
378
|
+
const result = maxWithdrawable.greaterThan(0)
|
|
379
|
+
? maxWithdrawable
|
|
380
|
+
: new Web3Number("0", collateral.decimals);
|
|
265
381
|
const usdValue = await this.getUSDValue(collateral, result);
|
|
266
382
|
const debtUSD = debtPosition.usdValue;
|
|
267
|
-
logger.verbose(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
383
|
+
logger.verbose(
|
|
384
|
+
`VesuMultiplyAdapter: Debt USD: ${debtUSD}, collateral USD: ${usdValue}`
|
|
385
|
+
);
|
|
386
|
+
const apys = await Promise.all([
|
|
387
|
+
this.getAPY({ asset: collateral, isDebt: false }),
|
|
388
|
+
this.getAPY({ asset: debt, isDebt: true }),
|
|
389
|
+
]);
|
|
390
|
+
logger.verbose(
|
|
391
|
+
`VesuMultiplyAdapter: Apys: ${apys[0].apy}, ${apys[1].apy}`
|
|
392
|
+
);
|
|
393
|
+
const netAPY =
|
|
394
|
+
usdValue - debtUSD > 0
|
|
395
|
+
? (apys[0].apy * usdValue + apys[1].apy * debtUSD) /
|
|
396
|
+
(usdValue - debtUSD)
|
|
397
|
+
: 0;
|
|
398
|
+
logger.verbose(
|
|
399
|
+
`VesuMultiplyAdapter: Max withdraw amount: ${result.toNumber()}, netAPY: ${netAPY}`
|
|
400
|
+
);
|
|
272
401
|
return {
|
|
273
402
|
tokenInfo: collateral,
|
|
274
403
|
amount: result,
|
|
@@ -276,58 +405,71 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
276
405
|
remarks: "Max withdraw based on health factor",
|
|
277
406
|
apy: {
|
|
278
407
|
apy: netAPY,
|
|
279
|
-
type: APYType.BASE
|
|
408
|
+
type: APYType.BASE,
|
|
280
409
|
},
|
|
281
|
-
protocol: this.protocol
|
|
410
|
+
protocol: this.protocol,
|
|
282
411
|
};
|
|
283
412
|
} catch (error) {
|
|
284
|
-
logger.error(
|
|
413
|
+
logger.error(
|
|
414
|
+
`VesuMultiplyAdapter: Error calculating max withdraw:`,
|
|
415
|
+
error
|
|
416
|
+
);
|
|
285
417
|
throw error;
|
|
286
418
|
}
|
|
287
419
|
}
|
|
288
420
|
|
|
289
421
|
protected _getDepositLeaf(): {
|
|
290
|
-
target: ContractAddr
|
|
291
|
-
method: string
|
|
292
|
-
packedArguments: bigint[]
|
|
293
|
-
sanitizer: ContractAddr
|
|
294
|
-
id: string
|
|
422
|
+
target: ContractAddr;
|
|
423
|
+
method: string;
|
|
424
|
+
packedArguments: bigint[];
|
|
425
|
+
sanitizer: ContractAddr;
|
|
426
|
+
id: string;
|
|
295
427
|
}[] {
|
|
296
428
|
const collateral = this.config.collateral;
|
|
297
429
|
const debt = this.config.debt;
|
|
298
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
299
|
-
|
|
430
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
431
|
+
this.config.poolId
|
|
432
|
+
);
|
|
433
|
+
const vesuMultiply = isV2
|
|
434
|
+
? this.vesuAdapter.VESU_MULTIPLY
|
|
435
|
+
: this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
300
436
|
|
|
301
437
|
return [
|
|
302
438
|
// Approval step for collateral
|
|
303
439
|
{
|
|
304
440
|
target: collateral.address,
|
|
305
|
-
method:
|
|
441
|
+
method: "approve",
|
|
306
442
|
packedArguments: [
|
|
307
443
|
vesuMultiply.toBigInt(), // spender
|
|
308
444
|
],
|
|
309
445
|
sanitizer: SIMPLE_SANITIZER,
|
|
310
446
|
// amc = approve multiply collateral
|
|
311
|
-
id: `amc_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
447
|
+
id: `amc_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
448
|
+
debt.symbol
|
|
449
|
+
}`,
|
|
312
450
|
},
|
|
313
451
|
// Switch delegation on
|
|
314
452
|
{
|
|
315
453
|
target: vesuSingleton,
|
|
316
|
-
method:
|
|
317
|
-
packedArguments: isV2
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
454
|
+
method: "modify_delegation",
|
|
455
|
+
packedArguments: isV2
|
|
456
|
+
? [
|
|
457
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
458
|
+
]
|
|
459
|
+
: [
|
|
460
|
+
this.config.poolId.toBigInt(),
|
|
461
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
462
|
+
],
|
|
323
463
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
324
464
|
// sd1 = switch delegation on
|
|
325
|
-
id: `sd1_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
465
|
+
id: `sd1_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
466
|
+
debt.symbol
|
|
467
|
+
}`,
|
|
326
468
|
},
|
|
327
469
|
// Vesu multiply call
|
|
328
470
|
{
|
|
329
471
|
target: vesuMultiply,
|
|
330
|
-
method:
|
|
472
|
+
method: "modify_lever",
|
|
331
473
|
packedArguments: [
|
|
332
474
|
this.config.poolId.toBigInt(),
|
|
333
475
|
collateral.address.toBigInt(),
|
|
@@ -336,34 +478,44 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
336
478
|
],
|
|
337
479
|
sanitizer: SIMPLE_SANITIZER_V2,
|
|
338
480
|
// vm = vesu multiply
|
|
339
|
-
id: `vm_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
481
|
+
id: `vm_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
482
|
+
debt.symbol
|
|
483
|
+
}`,
|
|
340
484
|
},
|
|
341
485
|
// Switch delegation off
|
|
342
486
|
{
|
|
343
487
|
target: vesuSingleton,
|
|
344
|
-
method:
|
|
345
|
-
packedArguments: isV2
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
488
|
+
method: "modify_delegation",
|
|
489
|
+
packedArguments: isV2
|
|
490
|
+
? [
|
|
491
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
492
|
+
]
|
|
493
|
+
: [
|
|
494
|
+
this.config.poolId.toBigInt(),
|
|
495
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
496
|
+
],
|
|
351
497
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
352
498
|
// sd2 = switch delegation off
|
|
353
|
-
id: `sd2_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
354
|
-
|
|
499
|
+
id: `sd2_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
500
|
+
debt.symbol
|
|
501
|
+
}`,
|
|
502
|
+
},
|
|
355
503
|
];
|
|
356
504
|
}
|
|
357
505
|
|
|
358
506
|
protected _getWithdrawLeaf(): {
|
|
359
|
-
target: ContractAddr
|
|
360
|
-
method: string
|
|
361
|
-
packedArguments: bigint[]
|
|
362
|
-
sanitizer: ContractAddr
|
|
363
|
-
id: string
|
|
507
|
+
target: ContractAddr;
|
|
508
|
+
method: string;
|
|
509
|
+
packedArguments: bigint[];
|
|
510
|
+
sanitizer: ContractAddr;
|
|
511
|
+
id: string;
|
|
364
512
|
}[] {
|
|
365
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
366
|
-
|
|
513
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
514
|
+
this.config.poolId
|
|
515
|
+
);
|
|
516
|
+
const vesuMultiply = isV2
|
|
517
|
+
? this.vesuAdapter.VESU_MULTIPLY
|
|
518
|
+
: this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
367
519
|
const collateral = this.config.collateral;
|
|
368
520
|
const debt = this.config.debt;
|
|
369
521
|
|
|
@@ -371,21 +523,25 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
371
523
|
// Switch delegation on
|
|
372
524
|
{
|
|
373
525
|
target: vesuSingleton,
|
|
374
|
-
method:
|
|
375
|
-
packedArguments: isV2
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
526
|
+
method: "modify_delegation",
|
|
527
|
+
packedArguments: isV2
|
|
528
|
+
? [
|
|
529
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
530
|
+
]
|
|
531
|
+
: [
|
|
532
|
+
this.config.poolId.toBigInt(),
|
|
533
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
534
|
+
],
|
|
381
535
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
382
536
|
// sdow = switch delegation on withdraw
|
|
383
|
-
id: `sdow_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
537
|
+
id: `sdow_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
538
|
+
debt.symbol
|
|
539
|
+
}`,
|
|
384
540
|
},
|
|
385
541
|
// Vesu multiply call
|
|
386
542
|
{
|
|
387
543
|
target: vesuMultiply,
|
|
388
|
-
method:
|
|
544
|
+
method: "modify_lever",
|
|
389
545
|
packedArguments: [
|
|
390
546
|
this.config.poolId.toBigInt(),
|
|
391
547
|
this.config.collateral.address.toBigInt(),
|
|
@@ -394,59 +550,85 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
394
550
|
],
|
|
395
551
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
396
552
|
// vmw = vesu multiply withdraw
|
|
397
|
-
id: `vmw_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
553
|
+
id: `vmw_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
554
|
+
debt.symbol
|
|
555
|
+
}`,
|
|
398
556
|
},
|
|
399
557
|
// Switch delegation off
|
|
400
558
|
{
|
|
401
559
|
target: vesuSingleton,
|
|
402
|
-
method:
|
|
403
|
-
packedArguments: isV2
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
560
|
+
method: "modify_delegation",
|
|
561
|
+
packedArguments: isV2
|
|
562
|
+
? [
|
|
563
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
564
|
+
]
|
|
565
|
+
: [
|
|
566
|
+
this.config.poolId.toBigInt(),
|
|
567
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
568
|
+
],
|
|
409
569
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
410
570
|
// sdofw = switch delegation off withdraw
|
|
411
|
-
id: `sdofw_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
412
|
-
|
|
571
|
+
id: `sdofw_${this.config.poolId.shortString()}_${collateral.symbol}_${
|
|
572
|
+
debt.symbol
|
|
573
|
+
}`,
|
|
574
|
+
},
|
|
413
575
|
];
|
|
414
576
|
}
|
|
415
577
|
|
|
416
578
|
getDepositAdapter(): AdapterLeafType<DepositParams> {
|
|
417
579
|
const leafConfigs = this._getDepositLeaf();
|
|
418
|
-
const leaves = leafConfigs.map(config => {
|
|
580
|
+
const leaves = leafConfigs.map((config) => {
|
|
419
581
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
420
|
-
const leaf = this.constructSimpleLeafData(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
582
|
+
const leaf = this.constructSimpleLeafData(
|
|
583
|
+
{
|
|
584
|
+
id: id,
|
|
585
|
+
target,
|
|
586
|
+
method,
|
|
587
|
+
packedArguments,
|
|
588
|
+
},
|
|
589
|
+
sanitizer
|
|
590
|
+
);
|
|
426
591
|
return leaf;
|
|
427
592
|
});
|
|
428
|
-
return {
|
|
593
|
+
return {
|
|
594
|
+
leaves,
|
|
595
|
+
callConstructor: this.getDepositCall.bind(
|
|
596
|
+
this
|
|
597
|
+
) as unknown as GenerateCallFn<DepositParams>,
|
|
598
|
+
};
|
|
429
599
|
}
|
|
430
600
|
|
|
431
601
|
getWithdrawAdapter(): AdapterLeafType<WithdrawParams> {
|
|
432
602
|
const leafConfigs = this._getWithdrawLeaf();
|
|
433
|
-
const leaves = leafConfigs.map(config => {
|
|
603
|
+
const leaves = leafConfigs.map((config) => {
|
|
434
604
|
const { target, method, packedArguments, sanitizer, id } = config;
|
|
435
|
-
const leaf = this.constructSimpleLeafData(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
605
|
+
const leaf = this.constructSimpleLeafData(
|
|
606
|
+
{
|
|
607
|
+
id: id,
|
|
608
|
+
target,
|
|
609
|
+
method,
|
|
610
|
+
packedArguments,
|
|
611
|
+
},
|
|
612
|
+
sanitizer
|
|
613
|
+
);
|
|
441
614
|
return leaf;
|
|
442
615
|
});
|
|
443
|
-
return {
|
|
616
|
+
return {
|
|
617
|
+
leaves,
|
|
618
|
+
callConstructor: this.getWithdrawCall.bind(
|
|
619
|
+
this
|
|
620
|
+
) as unknown as GenerateCallFn<WithdrawParams>,
|
|
621
|
+
};
|
|
444
622
|
}
|
|
445
623
|
|
|
446
624
|
async getDepositCall(params: DepositParams): Promise<ManageCall[]> {
|
|
447
625
|
const collateral = this.config.collateral;
|
|
448
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
449
|
-
|
|
626
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
627
|
+
this.config.poolId
|
|
628
|
+
);
|
|
629
|
+
const vesuMultiply = isV2
|
|
630
|
+
? this.vesuAdapter.VESU_MULTIPLY
|
|
631
|
+
: this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
450
632
|
|
|
451
633
|
const uint256MarginAmount = uint256.bnToUint256(params.amount.toWei());
|
|
452
634
|
|
|
@@ -456,61 +638,69 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
456
638
|
sanitizer: SIMPLE_SANITIZER,
|
|
457
639
|
call: {
|
|
458
640
|
contractAddress: collateral.address,
|
|
459
|
-
selector: hash.getSelectorFromName(
|
|
641
|
+
selector: hash.getSelectorFromName("approve"),
|
|
460
642
|
calldata: [
|
|
461
643
|
vesuMultiply.toBigInt(), // spender
|
|
462
644
|
toBigInt(uint256MarginAmount.low.toString()), // amount low
|
|
463
645
|
toBigInt(uint256MarginAmount.high.toString()), // amount high
|
|
464
|
-
]
|
|
465
|
-
}
|
|
646
|
+
],
|
|
647
|
+
},
|
|
466
648
|
},
|
|
467
649
|
// Switch delegation on
|
|
468
650
|
{
|
|
469
651
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
470
652
|
call: {
|
|
471
653
|
contractAddress: vesuSingleton,
|
|
472
|
-
selector: hash.getSelectorFromName(
|
|
473
|
-
calldata: isV2
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
654
|
+
selector: hash.getSelectorFromName("modify_delegation"),
|
|
655
|
+
calldata: isV2
|
|
656
|
+
? [
|
|
657
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
658
|
+
BigInt(1), // delegation: true
|
|
659
|
+
]
|
|
660
|
+
: [
|
|
661
|
+
this.config.poolId.toBigInt(),
|
|
662
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
663
|
+
BigInt(1), // delegation: true
|
|
664
|
+
],
|
|
665
|
+
},
|
|
482
666
|
},
|
|
483
667
|
// Vesu multiply call
|
|
484
668
|
{
|
|
485
669
|
sanitizer: SIMPLE_SANITIZER_V2,
|
|
486
670
|
call: {
|
|
487
671
|
contractAddress: vesuMultiply,
|
|
488
|
-
selector: hash.getSelectorFromName(
|
|
489
|
-
calldata: await this.getMultiplyCallCalldata(params, true)
|
|
490
|
-
}
|
|
672
|
+
selector: hash.getSelectorFromName("modify_lever"),
|
|
673
|
+
calldata: await this.getMultiplyCallCalldata(params, true),
|
|
674
|
+
},
|
|
491
675
|
},
|
|
492
676
|
// Switch delegation off
|
|
493
677
|
{
|
|
494
678
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
495
679
|
call: {
|
|
496
680
|
contractAddress: vesuSingleton,
|
|
497
|
-
selector: hash.getSelectorFromName(
|
|
498
|
-
calldata: isV2
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
681
|
+
selector: hash.getSelectorFromName("modify_delegation"),
|
|
682
|
+
calldata: isV2
|
|
683
|
+
? [
|
|
684
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
685
|
+
BigInt(0), // delegation: false
|
|
686
|
+
]
|
|
687
|
+
: [
|
|
688
|
+
this.config.poolId.toBigInt(),
|
|
689
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
690
|
+
BigInt(0), // delegation: false
|
|
691
|
+
],
|
|
692
|
+
},
|
|
693
|
+
},
|
|
508
694
|
];
|
|
509
695
|
}
|
|
510
696
|
|
|
511
697
|
async getWithdrawCall(params: WithdrawParams): Promise<ManageCall[]> {
|
|
512
|
-
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
513
|
-
|
|
698
|
+
const { addr: vesuSingleton, isV2 } = getVesuSingletonAddress(
|
|
699
|
+
this.config.poolId
|
|
700
|
+
);
|
|
701
|
+
const vesuMultiply = isV2
|
|
702
|
+
? this.vesuAdapter.VESU_MULTIPLY
|
|
703
|
+
: this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
514
704
|
|
|
515
705
|
return [
|
|
516
706
|
// Switch delegation on
|
|
@@ -518,118 +708,191 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
518
708
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
519
709
|
call: {
|
|
520
710
|
contractAddress: vesuSingleton,
|
|
521
|
-
selector: hash.getSelectorFromName(
|
|
522
|
-
calldata: isV2
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
711
|
+
selector: hash.getSelectorFromName("modify_delegation"),
|
|
712
|
+
calldata: isV2
|
|
713
|
+
? [
|
|
714
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
715
|
+
BigInt(1), // delegation: true
|
|
716
|
+
]
|
|
717
|
+
: [
|
|
718
|
+
this.config.poolId.toBigInt(),
|
|
719
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
720
|
+
BigInt(1), // delegation: true
|
|
721
|
+
],
|
|
722
|
+
},
|
|
531
723
|
},
|
|
532
724
|
// Vesu multiply call
|
|
533
725
|
{
|
|
534
726
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
535
727
|
call: {
|
|
536
728
|
contractAddress: vesuMultiply,
|
|
537
|
-
selector: hash.getSelectorFromName(
|
|
538
|
-
calldata: await this.getWithdrawalCalldata(params)
|
|
539
|
-
}
|
|
729
|
+
selector: hash.getSelectorFromName("modify_lever"),
|
|
730
|
+
calldata: await this.getWithdrawalCalldata(params),
|
|
731
|
+
},
|
|
540
732
|
},
|
|
541
733
|
// Switch delegation off
|
|
542
734
|
{
|
|
543
735
|
sanitizer: isV2 ? SIMPLE_SANITIZER_V2 : SIMPLE_SANITIZER,
|
|
544
736
|
call: {
|
|
545
737
|
contractAddress: vesuSingleton,
|
|
546
|
-
selector: hash.getSelectorFromName(
|
|
547
|
-
calldata: isV2
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
738
|
+
selector: hash.getSelectorFromName("modify_delegation"),
|
|
739
|
+
calldata: isV2
|
|
740
|
+
? [
|
|
741
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
742
|
+
BigInt(0), // delegation: false
|
|
743
|
+
]
|
|
744
|
+
: [
|
|
745
|
+
this.config.poolId.toBigInt(),
|
|
746
|
+
vesuMultiply.toBigInt(), // delegatee
|
|
747
|
+
BigInt(0), // delegation: false
|
|
748
|
+
],
|
|
749
|
+
},
|
|
750
|
+
},
|
|
557
751
|
];
|
|
558
752
|
}
|
|
559
753
|
|
|
560
|
-
private async getMultiplyCallCalldata(
|
|
561
|
-
|
|
754
|
+
private async getMultiplyCallCalldata(
|
|
755
|
+
params: DepositParams | WithdrawParams,
|
|
756
|
+
isDeposit: boolean
|
|
757
|
+
): Promise<bigint[]> {
|
|
758
|
+
logger.verbose(
|
|
759
|
+
`${
|
|
760
|
+
VesuMultiplyAdapter.name
|
|
761
|
+
}::getMultiplyCallCalldata params: ${JSON.stringify(
|
|
762
|
+
params
|
|
763
|
+
)}, isDeposit: ${isDeposit}, collateral: ${
|
|
764
|
+
this.config.collateral.symbol
|
|
765
|
+
}, debt: ${this.config.debt.symbol}`
|
|
766
|
+
);
|
|
562
767
|
const { isV2 } = getVesuSingletonAddress(this.config.poolId);
|
|
563
|
-
const vesuMultiply = isV2
|
|
564
|
-
|
|
768
|
+
const vesuMultiply = isV2
|
|
769
|
+
? this.vesuAdapter.VESU_MULTIPLY
|
|
770
|
+
: this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
771
|
+
|
|
565
772
|
// Create a temporary contract instance to populate the call
|
|
566
773
|
const multiplyContract = new Contract({
|
|
567
|
-
abi: VesuMultiplyAbi,
|
|
568
|
-
address: vesuMultiply.address,
|
|
569
|
-
providerOrAccount: this.config.networkConfig.provider
|
|
774
|
+
abi: VesuMultiplyAbi,
|
|
775
|
+
address: vesuMultiply.address,
|
|
776
|
+
providerOrAccount: this.config.networkConfig.provider,
|
|
570
777
|
});
|
|
571
778
|
|
|
572
779
|
// Configure swaps based on the operation
|
|
573
780
|
let leverSwap: Swap[] = [];
|
|
574
781
|
let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
575
782
|
|
|
576
|
-
const existingPositions = await this.vesuAdapter.getPositions(
|
|
577
|
-
|
|
783
|
+
const existingPositions = await this.vesuAdapter.getPositions(
|
|
784
|
+
this.config.networkConfig
|
|
785
|
+
);
|
|
786
|
+
const collateralisation = await this.vesuAdapter.getCollateralization(
|
|
787
|
+
this.config.networkConfig
|
|
788
|
+
);
|
|
578
789
|
const existingCollateralInfo = existingPositions[0];
|
|
579
790
|
const existingDebtInfo = existingPositions[1];
|
|
580
791
|
const isDexPriceRequired = existingDebtInfo.token.symbol !== "USDC";
|
|
581
|
-
logger.debug(`${
|
|
582
|
-
|
|
792
|
+
logger.debug(`${
|
|
793
|
+
VesuMultiplyAdapter.name
|
|
794
|
+
}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(
|
|
795
|
+
existingCollateralInfo
|
|
796
|
+
)},
|
|
797
|
+
existingDebtInfo: ${JSON.stringify(
|
|
798
|
+
existingDebtInfo
|
|
799
|
+
)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
583
800
|
|
|
584
801
|
// - Prices as seen by Vesu contracts, ideal for HF math
|
|
585
|
-
// Price 1 is ok as fallback bcz that would relatively price the
|
|
802
|
+
// Price 1 is ok as fallback bcz that would relatively price the
|
|
586
803
|
// collateral and debt as equal.
|
|
587
|
-
const collateralPrice =
|
|
588
|
-
collateralisation[0].usdValue
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
804
|
+
const collateralPrice =
|
|
805
|
+
collateralisation[0].usdValue > 0
|
|
806
|
+
? collateralisation[0].usdValue /
|
|
807
|
+
existingCollateralInfo.amount.toNumber()
|
|
808
|
+
: (await this.config.pricer.getPrice(this.config.collateral.symbol))
|
|
809
|
+
.price;
|
|
810
|
+
const debtPrice =
|
|
811
|
+
collateralisation[1].usdValue > 0
|
|
812
|
+
? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber()
|
|
813
|
+
: (await this.config.pricer.getPrice(this.config.debt.symbol)).price;
|
|
814
|
+
logger.debug(
|
|
815
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`
|
|
816
|
+
);
|
|
817
|
+
|
|
818
|
+
const legLTV = await this.vesuAdapter.getLTVConfig(
|
|
819
|
+
this.config.networkConfig
|
|
820
|
+
);
|
|
821
|
+
const ekuboQuoter = new EkuboQuoter(
|
|
822
|
+
this.config.networkConfig,
|
|
823
|
+
this.config.pricer
|
|
824
|
+
);
|
|
825
|
+
const dexPrice = isDexPriceRequired
|
|
826
|
+
? await ekuboQuoter.getDexPrice(
|
|
827
|
+
this.config.collateral,
|
|
828
|
+
this.config.debt,
|
|
829
|
+
this.config.quoteAmountToFetchPrice
|
|
830
|
+
)
|
|
831
|
+
: 1;
|
|
832
|
+
logger.verbose(
|
|
833
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall dexPrice: ${dexPrice}, ltv: ${legLTV}`
|
|
834
|
+
);
|
|
599
835
|
|
|
600
836
|
// compute optimal amount of collateral and debt post addition/removal
|
|
601
837
|
// target hf = collateral * collateralPrice * ltv / debt * debtPrice
|
|
602
|
-
// assuming X to be the usd amount of debt borrowed or repaied (negative).
|
|
838
|
+
// assuming X to be the usd amount of debt borrowed or repaied (negative).
|
|
603
839
|
// target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv / (debt * debtPrice + X)
|
|
604
840
|
// => X * target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv - (debt * debtPrice * target hf)
|
|
605
841
|
// => X * (target hf - ltv)= ((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)
|
|
606
842
|
// => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
|
|
607
843
|
|
|
608
|
-
const addedCollateral = params.amount
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
logger.verbose(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
844
|
+
const addedCollateral = params.amount.multipliedBy(isDeposit ? 1 : -1);
|
|
845
|
+
logger.verbose(
|
|
846
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`
|
|
847
|
+
);
|
|
848
|
+
const numeratorPart1 = existingCollateralInfo.amount
|
|
849
|
+
.plus(addedCollateral)
|
|
850
|
+
.multipliedBy(collateralPrice)
|
|
851
|
+
.multipliedBy(legLTV);
|
|
852
|
+
logger.verbose(
|
|
853
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`
|
|
854
|
+
);
|
|
855
|
+
const numeratorPart2 = existingDebtInfo.amount
|
|
856
|
+
.multipliedBy(debtPrice)
|
|
857
|
+
.multipliedBy(this.config.targetHealthFactor);
|
|
858
|
+
logger.verbose(
|
|
859
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`
|
|
860
|
+
);
|
|
861
|
+
const denominatorPart = this.config.targetHealthFactor - legLTV / dexPrice; // TODO Write reason for this. this dexPrice is some custom thing. this dexPrice is probably exchange rate (1 xWBTC in WBTC terms)
|
|
862
|
+
logger.verbose(
|
|
863
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`
|
|
864
|
+
);
|
|
865
|
+
const x_debt_usd = numeratorPart1
|
|
866
|
+
.minus(numeratorPart2)
|
|
867
|
+
.dividedBy(denominatorPart);
|
|
868
|
+
logger.verbose(
|
|
869
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`
|
|
870
|
+
);
|
|
871
|
+
logger.debug(
|
|
872
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`
|
|
873
|
+
);
|
|
620
874
|
|
|
621
875
|
// both in underlying
|
|
622
876
|
// debtAmount in debt units
|
|
623
|
-
let debtAmount = new Web3Number(
|
|
877
|
+
let debtAmount = new Web3Number(
|
|
878
|
+
x_debt_usd.dividedBy(debtPrice).toFixed(this.config.debt.decimals),
|
|
879
|
+
this.config.debt.decimals
|
|
880
|
+
);
|
|
624
881
|
const marginAmount = addedCollateral;
|
|
625
882
|
const collateralToken = this.config.collateral;
|
|
626
883
|
const debtToken = this.config.debt;
|
|
627
|
-
const debtAmountInCollateralUnits = new Web3Number(
|
|
628
|
-
|
|
884
|
+
const debtAmountInCollateralUnits = new Web3Number(
|
|
885
|
+
debtAmount
|
|
886
|
+
.multipliedBy(debtPrice)
|
|
887
|
+
.dividedBy(collateralPrice)
|
|
888
|
+
.multipliedBy(10 ** collateralToken.decimals)
|
|
889
|
+
.toFixed(0),
|
|
890
|
+
collateralToken.decimals
|
|
891
|
+
);
|
|
892
|
+
|
|
629
893
|
// increase multiply lever or not
|
|
630
894
|
const isIncrease = debtAmount.greaterThanOrEqualTo(0);
|
|
631
895
|
|
|
632
|
-
|
|
633
896
|
// due to directional limitations in multiply contract
|
|
634
897
|
if (isIncrease && debtAmount.lessThan(0)) {
|
|
635
898
|
// we are increasing lever but math says reduce debt
|
|
@@ -640,23 +903,37 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
640
903
|
// - so just set debt 0
|
|
641
904
|
debtAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
642
905
|
}
|
|
643
|
-
logger.verbose(
|
|
906
|
+
logger.verbose(
|
|
907
|
+
`${VesuMultiplyAdapter.name}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`
|
|
908
|
+
);
|
|
644
909
|
if (!debtAmount.isZero()) {
|
|
645
910
|
// Get swap quote for leverage operation
|
|
646
911
|
// Determine swap direction based on operation type
|
|
647
|
-
|
|
648
|
-
|
|
912
|
+
|
|
913
|
+
try {
|
|
649
914
|
const swapQuote = await ekuboQuoter.getQuote(
|
|
650
915
|
collateralToken.address.address,
|
|
651
916
|
debtToken.address.address,
|
|
652
|
-
debtAmountInCollateralUnits.multipliedBy(-1)// negative for exact amount out
|
|
917
|
+
debtAmountInCollateralUnits.multipliedBy(-1) // negative for exact amount out
|
|
653
918
|
);
|
|
654
|
-
|
|
919
|
+
|
|
655
920
|
// todo add better slip checks
|
|
656
921
|
// Check price impact
|
|
657
|
-
if (swapQuote.price_impact < 0.01) {
|
|
922
|
+
if (swapQuote.price_impact < 0.01) {
|
|
923
|
+
// 1% max price impact
|
|
658
924
|
// from and toToken param position reversed, to fetch the required quote and keep things generalised
|
|
659
|
-
|
|
925
|
+
|
|
926
|
+
leverSwap = debtAmount.isNegative()
|
|
927
|
+
? ekuboQuoter.getVesuMultiplyQuote(
|
|
928
|
+
swapQuote,
|
|
929
|
+
collateralToken,
|
|
930
|
+
debtToken
|
|
931
|
+
)
|
|
932
|
+
: ekuboQuoter.getVesuMultiplyQuote(
|
|
933
|
+
swapQuote,
|
|
934
|
+
debtToken,
|
|
935
|
+
collateralToken
|
|
936
|
+
);
|
|
660
937
|
//console.log("leverSwap", leverSwap[-1].token_amount);
|
|
661
938
|
//console.log(JSON.stringify(leverSwap));
|
|
662
939
|
// Calculate limit amount with slippage protection
|
|
@@ -672,215 +949,309 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
672
949
|
// For decrease: maximum amount of collateral used
|
|
673
950
|
// from collateral token to debt token
|
|
674
951
|
//leverSwapLimitAmount = await ekuboQuoter.getSwapLimitAmount(collateralToken, debtToken, debtAmountInCollateralUnits.multipliedBy(-1), MAX_SLIPPAGE);
|
|
675
|
-
leverSwapLimitAmount = debtAmount
|
|
952
|
+
leverSwapLimitAmount = debtAmount
|
|
953
|
+
.abs()
|
|
954
|
+
.multipliedBy(1 - MAX_SLIPPAGE);
|
|
676
955
|
//console.log("anotherleverSwapLimitAmount", anotherleverSwapLimitAmount, leverSwapLimitAmount);
|
|
677
956
|
} else {
|
|
678
|
-
leverSwapLimitAmount = Web3Number.fromWei(
|
|
957
|
+
leverSwapLimitAmount = Web3Number.fromWei(
|
|
958
|
+
0,
|
|
959
|
+
this.config.debt.decimals
|
|
960
|
+
);
|
|
679
961
|
}
|
|
680
962
|
await new Promise((resolve) => setTimeout(resolve, 10000));
|
|
681
963
|
//console.log("leverSwapLimitAmount", leverSwapLimitAmount);
|
|
682
964
|
} else {
|
|
683
|
-
throw new Error(
|
|
965
|
+
throw new Error(
|
|
966
|
+
`VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
|
|
967
|
+
);
|
|
684
968
|
}
|
|
685
969
|
} catch (error) {
|
|
686
|
-
throw new Error(
|
|
970
|
+
throw new Error(
|
|
971
|
+
`VesuMultiplyAdapter: Failed to get swap quote: ${error}`
|
|
972
|
+
);
|
|
687
973
|
}
|
|
688
974
|
}
|
|
689
|
-
|
|
690
|
-
const multiplyParams = await this.getLeverParams(
|
|
691
|
-
|
|
692
|
-
|
|
975
|
+
|
|
976
|
+
const multiplyParams = await this.getLeverParams(
|
|
977
|
+
isIncrease,
|
|
978
|
+
params,
|
|
979
|
+
leverSwap,
|
|
980
|
+
leverSwapLimitAmount
|
|
981
|
+
);
|
|
982
|
+
const call = multiplyContract.populate("modify_lever", {
|
|
983
|
+
modify_lever_params: this.formatMultiplyParams(
|
|
984
|
+
isIncrease,
|
|
985
|
+
multiplyParams
|
|
986
|
+
),
|
|
693
987
|
});
|
|
694
988
|
|
|
695
989
|
return call.calldata as bigint[];
|
|
696
990
|
}
|
|
697
991
|
|
|
698
|
-
private async getLeverParams(
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
992
|
+
private async getLeverParams(
|
|
993
|
+
isIncrease: boolean,
|
|
994
|
+
params: DepositParams | WithdrawParams,
|
|
995
|
+
leverSwap: Swap[],
|
|
996
|
+
leverSwapLimitAmount: Web3Number
|
|
997
|
+
): Promise<IncreaseLeverParams | DecreaseLeverParams> {
|
|
998
|
+
const multiplyParams: IncreaseLeverParams | DecreaseLeverParams = isIncrease
|
|
999
|
+
? {
|
|
1000
|
+
user: this.config.vaultAllocator,
|
|
1001
|
+
pool_id: this.config.poolId,
|
|
1002
|
+
collateral_asset: this.config.collateral.address,
|
|
1003
|
+
debt_asset: this.config.debt.address,
|
|
1004
|
+
recipient: this.config.vaultAllocator,
|
|
1005
|
+
add_margin: params.amount, // multiplied by collateral decimals in format
|
|
1006
|
+
margin_swap: [],
|
|
1007
|
+
margin_swap_limit_amount: Web3Number.fromWei(
|
|
1008
|
+
0,
|
|
1009
|
+
this.config.collateral.decimals
|
|
1010
|
+
),
|
|
1011
|
+
lever_swap: leverSwap,
|
|
1012
|
+
lever_swap_limit_amount: leverSwapLimitAmount,
|
|
1013
|
+
}
|
|
1014
|
+
: {
|
|
1015
|
+
user: this.config.vaultAllocator,
|
|
1016
|
+
pool_id: this.config.poolId,
|
|
1017
|
+
collateral_asset: this.config.collateral.address,
|
|
1018
|
+
debt_asset: this.config.debt.address,
|
|
1019
|
+
recipient: this.config.vaultAllocator,
|
|
1020
|
+
sub_margin: params.amount,
|
|
1021
|
+
lever_swap: leverSwap,
|
|
1022
|
+
lever_swap_limit_amount: leverSwapLimitAmount,
|
|
1023
|
+
lever_swap_weights: [],
|
|
1024
|
+
withdraw_swap: [],
|
|
1025
|
+
withdraw_swap_limit_amount: Web3Number.fromWei(
|
|
1026
|
+
0,
|
|
1027
|
+
this.config.collateral.decimals
|
|
1028
|
+
),
|
|
1029
|
+
withdraw_swap_weights: [],
|
|
1030
|
+
close_position: false,
|
|
1031
|
+
};
|
|
725
1032
|
return multiplyParams;
|
|
726
1033
|
}
|
|
727
1034
|
|
|
728
|
-
private async getWithdrawalCalldata(
|
|
1035
|
+
private async getWithdrawalCalldata(
|
|
1036
|
+
params: WithdrawParams
|
|
1037
|
+
): Promise<bigint[]> {
|
|
729
1038
|
//params.amount must be in btc here
|
|
730
1039
|
const { isV2 } = getVesuSingletonAddress(this.config.poolId);
|
|
731
|
-
const vesuMultiply = isV2
|
|
1040
|
+
const vesuMultiply = isV2
|
|
1041
|
+
? this.vesuAdapter.VESU_MULTIPLY
|
|
1042
|
+
: this.vesuAdapter.VESU_MULTIPLY_V1;
|
|
732
1043
|
const multiplyContract = new Contract({
|
|
733
|
-
abi: VesuMultiplyAbi,
|
|
734
|
-
address: vesuMultiply.address,
|
|
735
|
-
providerOrAccount: this.config.networkConfig.provider
|
|
1044
|
+
abi: VesuMultiplyAbi,
|
|
1045
|
+
address: vesuMultiply.address,
|
|
1046
|
+
providerOrAccount: this.config.networkConfig.provider,
|
|
736
1047
|
});
|
|
737
1048
|
let leverSwap: Swap[] = [];
|
|
738
1049
|
let leverSwapLimitAmount = Web3Number.fromWei(0, this.config.debt.decimals);
|
|
739
|
-
const existingPositions = await this.vesuAdapter.getPositions(
|
|
1050
|
+
const existingPositions = await this.vesuAdapter.getPositions(
|
|
1051
|
+
this.config.networkConfig
|
|
1052
|
+
);
|
|
740
1053
|
const existingCollateralInfo = existingPositions[0];
|
|
741
1054
|
const existingDebtInfo = existingPositions[1];
|
|
742
1055
|
const collateralToken = this.config.collateral;
|
|
743
1056
|
const debtToken = this.config.debt;
|
|
744
|
-
const collateralPrice = await this.config.pricer.getPrice(
|
|
1057
|
+
const collateralPrice = await this.config.pricer.getPrice(
|
|
1058
|
+
collateralToken.symbol
|
|
1059
|
+
);
|
|
745
1060
|
const debtPrice = await this.config.pricer.getPrice(debtToken.symbol);
|
|
746
1061
|
// the debt amount is negative as we are reducing debt to withdraw
|
|
747
1062
|
const { deltadebtAmountUnits: debtAmountToRepay } =
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
1063
|
+
calculateDebtReductionAmountForWithdrawal(
|
|
1064
|
+
existingDebtInfo.amount,
|
|
1065
|
+
existingCollateralInfo.amount,
|
|
1066
|
+
MAX_LIQUIDATION_RATIO,
|
|
1067
|
+
params.amount,
|
|
1068
|
+
collateralPrice.price,
|
|
1069
|
+
debtPrice.price,
|
|
1070
|
+
debtToken.decimals
|
|
1071
|
+
);
|
|
757
1072
|
//console.log("debtAmountToRepay", debtAmountToRepay);
|
|
758
|
-
if(!debtAmountToRepay) {
|
|
1073
|
+
if (!debtAmountToRepay) {
|
|
759
1074
|
throw new Error("error calculating debt amount to repay");
|
|
760
1075
|
}
|
|
761
|
-
const ekuboQuoter = new EkuboQuoter(
|
|
762
|
-
|
|
1076
|
+
const ekuboQuoter = new EkuboQuoter(
|
|
1077
|
+
this.config.networkConfig,
|
|
1078
|
+
this.config.pricer
|
|
1079
|
+
);
|
|
1080
|
+
const debtInDebtUnits = new Web3Number(
|
|
1081
|
+
debtAmountToRepay,
|
|
1082
|
+
debtToken.decimals
|
|
1083
|
+
)
|
|
1084
|
+
.dividedBy(debtPrice.price)
|
|
1085
|
+
.multipliedBy(10 ** debtToken.decimals);
|
|
763
1086
|
const swapQuote = await ekuboQuoter.getQuote(
|
|
764
1087
|
debtToken.address.address,
|
|
765
1088
|
collateralToken.address.address,
|
|
766
1089
|
debtInDebtUnits
|
|
767
|
-
)
|
|
1090
|
+
);
|
|
768
1091
|
const MAX_SLIPPAGE = 0.002; // 0.2% slippag
|
|
769
|
-
if(swapQuote.price_impact < 0.0025) {
|
|
770
|
-
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
1092
|
+
if (swapQuote.price_impact < 0.0025) {
|
|
1093
|
+
leverSwap = ekuboQuoter.getVesuMultiplyQuote(
|
|
1094
|
+
swapQuote,
|
|
1095
|
+
collateralToken,
|
|
1096
|
+
debtToken
|
|
1097
|
+
);
|
|
771
1098
|
} else {
|
|
772
|
-
logger.error(
|
|
1099
|
+
logger.error(
|
|
1100
|
+
`VesuMultiplyAdapter: Price impact too high (${swapQuote.price_impact}), skipping swap`
|
|
1101
|
+
);
|
|
773
1102
|
}
|
|
774
1103
|
|
|
775
|
-
leverSwapLimitAmount = new Web3Number(debtAmountToRepay, debtToken.decimals)
|
|
1104
|
+
leverSwapLimitAmount = new Web3Number(debtAmountToRepay, debtToken.decimals)
|
|
1105
|
+
.abs()
|
|
1106
|
+
.multipliedBy(1 + MAX_SLIPPAGE);
|
|
776
1107
|
//leverSwapLimitAmount = await ekuboQuoter.getSwapLimitAmount(debtToken, collateralToken, debtInCollateralUnits, MAX_SLIPPAGE);
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1108
|
+
const multiplyParams = await this.getLeverParams(
|
|
1109
|
+
false,
|
|
1110
|
+
params,
|
|
1111
|
+
leverSwap,
|
|
1112
|
+
leverSwapLimitAmount
|
|
1113
|
+
);
|
|
1114
|
+
const call = multiplyContract.populate("modify_lever", {
|
|
1115
|
+
modify_lever_params: this.formatMultiplyParams(false, multiplyParams),
|
|
780
1116
|
});
|
|
781
1117
|
return call.calldata as bigint[];
|
|
782
1118
|
}
|
|
783
1119
|
|
|
784
|
-
formatMultiplyParams(
|
|
1120
|
+
formatMultiplyParams(
|
|
1121
|
+
isIncrease: boolean,
|
|
1122
|
+
params: IncreaseLeverParams | DecreaseLeverParams
|
|
1123
|
+
) {
|
|
785
1124
|
if (isIncrease) {
|
|
786
1125
|
const _params = params as IncreaseLeverParams;
|
|
787
1126
|
return {
|
|
788
|
-
action: new CairoCustomEnum({
|
|
1127
|
+
action: new CairoCustomEnum({
|
|
1128
|
+
IncreaseLever: {
|
|
1129
|
+
pool_id: _params.pool_id.toBigInt(),
|
|
1130
|
+
collateral_asset: _params.collateral_asset.toBigInt(),
|
|
1131
|
+
debt_asset: _params.debt_asset.toBigInt(),
|
|
1132
|
+
user: _params.user.toBigInt(),
|
|
1133
|
+
add_margin: BigInt(_params.add_margin.toWei()),
|
|
1134
|
+
margin_swap: _params.margin_swap.map((swap) => ({
|
|
1135
|
+
route: swap.route.map((route) => ({
|
|
1136
|
+
pool_key: {
|
|
1137
|
+
token0: route.pool_key.token0.toBigInt(),
|
|
1138
|
+
token1: route.pool_key.token1.toBigInt(),
|
|
1139
|
+
fee: route.pool_key.fee,
|
|
1140
|
+
tick_spacing: route.pool_key.tick_spacing,
|
|
1141
|
+
extension: BigInt(
|
|
1142
|
+
num.hexToDecimalString(route.pool_key.extension)
|
|
1143
|
+
),
|
|
1144
|
+
},
|
|
1145
|
+
sqrt_ratio_limit: uint256.bnToUint256(
|
|
1146
|
+
route.sqrt_ratio_limit.toWei()
|
|
1147
|
+
),
|
|
1148
|
+
skip_ahead: BigInt(100),
|
|
1149
|
+
})),
|
|
1150
|
+
token_amount: {
|
|
1151
|
+
token: swap.token_amount.token.toBigInt(),
|
|
1152
|
+
amount: swap.token_amount.amount.toI129(),
|
|
1153
|
+
},
|
|
1154
|
+
})),
|
|
1155
|
+
margin_swap_limit_amount: BigInt(
|
|
1156
|
+
_params.margin_swap_limit_amount.toWei()
|
|
1157
|
+
),
|
|
1158
|
+
lever_swap: _params.lever_swap.map((swap) => ({
|
|
1159
|
+
route: swap.route.map((route) => ({
|
|
1160
|
+
pool_key: {
|
|
1161
|
+
token0: route.pool_key.token0.toBigInt(),
|
|
1162
|
+
token1: route.pool_key.token1.toBigInt(),
|
|
1163
|
+
fee: route.pool_key.fee,
|
|
1164
|
+
tick_spacing: route.pool_key.tick_spacing,
|
|
1165
|
+
extension: BigInt(
|
|
1166
|
+
num.hexToDecimalString(route.pool_key.extension)
|
|
1167
|
+
),
|
|
1168
|
+
},
|
|
1169
|
+
sqrt_ratio_limit: uint256.bnToUint256(
|
|
1170
|
+
route.sqrt_ratio_limit.toWei()
|
|
1171
|
+
),
|
|
1172
|
+
skip_ahead: BigInt(0),
|
|
1173
|
+
})),
|
|
1174
|
+
token_amount: {
|
|
1175
|
+
token: swap.token_amount.token.toBigInt(),
|
|
1176
|
+
amount: swap.token_amount.amount.toI129(),
|
|
1177
|
+
},
|
|
1178
|
+
})),
|
|
1179
|
+
lever_swap_limit_amount: BigInt(
|
|
1180
|
+
_params.lever_swap_limit_amount.toWei()
|
|
1181
|
+
),
|
|
1182
|
+
},
|
|
1183
|
+
}),
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
const _params = params as DecreaseLeverParams;
|
|
1188
|
+
return {
|
|
1189
|
+
action: new CairoCustomEnum({
|
|
1190
|
+
DecreaseLever: {
|
|
789
1191
|
pool_id: _params.pool_id.toBigInt(),
|
|
790
1192
|
collateral_asset: _params.collateral_asset.toBigInt(),
|
|
791
1193
|
debt_asset: _params.debt_asset.toBigInt(),
|
|
792
1194
|
user: _params.user.toBigInt(),
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
1195
|
+
sub_margin: BigInt(_params.sub_margin.toWei()),
|
|
1196
|
+
recipient: _params.recipient.toBigInt(),
|
|
1197
|
+
lever_swap: _params.lever_swap.map((swap) => ({
|
|
1198
|
+
route: swap.route.map((route) => ({
|
|
796
1199
|
pool_key: {
|
|
797
1200
|
token0: route.pool_key.token0.toBigInt(),
|
|
798
1201
|
token1: route.pool_key.token1.toBigInt(),
|
|
799
1202
|
fee: route.pool_key.fee,
|
|
800
1203
|
tick_spacing: route.pool_key.tick_spacing,
|
|
801
|
-
extension:
|
|
1204
|
+
extension: ContractAddr.from(
|
|
1205
|
+
route.pool_key.extension
|
|
1206
|
+
).toBigInt(),
|
|
802
1207
|
},
|
|
803
|
-
sqrt_ratio_limit: uint256.bnToUint256(
|
|
804
|
-
|
|
1208
|
+
sqrt_ratio_limit: uint256.bnToUint256(
|
|
1209
|
+
route.sqrt_ratio_limit.toWei()
|
|
1210
|
+
),
|
|
1211
|
+
skip_ahead: BigInt(route.skip_ahead.toWei()),
|
|
805
1212
|
})),
|
|
806
1213
|
token_amount: {
|
|
807
1214
|
token: swap.token_amount.token.toBigInt(),
|
|
808
|
-
amount: swap.token_amount.amount.toI129()
|
|
809
|
-
}
|
|
1215
|
+
amount: swap.token_amount.amount.toI129(),
|
|
1216
|
+
},
|
|
810
1217
|
})),
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
1218
|
+
lever_swap_limit_amount: BigInt(
|
|
1219
|
+
_params.lever_swap_limit_amount.toWei()
|
|
1220
|
+
),
|
|
1221
|
+
lever_swap_weights: _params.lever_swap_weights.map((weight) =>
|
|
1222
|
+
BigInt(weight.toWei())
|
|
1223
|
+
),
|
|
1224
|
+
withdraw_swap: _params.withdraw_swap.map((swap) => ({
|
|
1225
|
+
route: swap.route.map((route) => ({
|
|
814
1226
|
pool_key: {
|
|
815
1227
|
token0: route.pool_key.token0.toBigInt(),
|
|
816
1228
|
token1: route.pool_key.token1.toBigInt(),
|
|
817
1229
|
fee: route.pool_key.fee,
|
|
818
1230
|
tick_spacing: route.pool_key.tick_spacing,
|
|
819
|
-
extension:
|
|
1231
|
+
extension: ContractAddr.from(
|
|
1232
|
+
route.pool_key.extension
|
|
1233
|
+
).toBigInt(),
|
|
820
1234
|
},
|
|
821
|
-
sqrt_ratio_limit: uint256.bnToUint256(
|
|
822
|
-
|
|
1235
|
+
sqrt_ratio_limit: uint256.bnToUint256(
|
|
1236
|
+
route.sqrt_ratio_limit.toWei()
|
|
1237
|
+
),
|
|
1238
|
+
skip_ahead: BigInt(route.skip_ahead.toWei()),
|
|
823
1239
|
})),
|
|
824
1240
|
token_amount: {
|
|
825
1241
|
token: swap.token_amount.token.toBigInt(),
|
|
826
|
-
amount: swap.token_amount.amount.toI129()
|
|
827
|
-
}
|
|
828
|
-
})),
|
|
829
|
-
lever_swap_limit_amount: BigInt(_params.lever_swap_limit_amount.toWei()),
|
|
830
|
-
} }),
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const _params = params as DecreaseLeverParams;
|
|
835
|
-
return {
|
|
836
|
-
action: new CairoCustomEnum({ DecreaseLever: {
|
|
837
|
-
pool_id: _params.pool_id.toBigInt(),
|
|
838
|
-
collateral_asset: _params.collateral_asset.toBigInt(),
|
|
839
|
-
debt_asset: _params.debt_asset.toBigInt(),
|
|
840
|
-
user: _params.user.toBigInt(),
|
|
841
|
-
sub_margin: BigInt(_params.sub_margin.toWei()),
|
|
842
|
-
recipient: _params.recipient.toBigInt(),
|
|
843
|
-
lever_swap: _params.lever_swap.map(swap => ({
|
|
844
|
-
route: swap.route.map(route => ({
|
|
845
|
-
pool_key: {
|
|
846
|
-
token0: route.pool_key.token0.toBigInt(),
|
|
847
|
-
token1: route.pool_key.token1.toBigInt(),
|
|
848
|
-
fee: route.pool_key.fee,
|
|
849
|
-
tick_spacing: route.pool_key.tick_spacing,
|
|
850
|
-
extension: ContractAddr.from(route.pool_key.extension).toBigInt(),
|
|
851
|
-
},
|
|
852
|
-
sqrt_ratio_limit: uint256.bnToUint256(route.sqrt_ratio_limit.toWei()),
|
|
853
|
-
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
854
|
-
})),
|
|
855
|
-
token_amount: {
|
|
856
|
-
token: swap.token_amount.token.toBigInt(),
|
|
857
|
-
amount: swap.token_amount.amount.toI129()
|
|
858
|
-
}
|
|
859
|
-
})),
|
|
860
|
-
lever_swap_limit_amount: BigInt(_params.lever_swap_limit_amount.toWei()),
|
|
861
|
-
lever_swap_weights: _params.lever_swap_weights.map(weight => BigInt(weight.toWei())),
|
|
862
|
-
withdraw_swap: _params.withdraw_swap.map(swap => ({
|
|
863
|
-
route: swap.route.map(route => ({
|
|
864
|
-
pool_key: {
|
|
865
|
-
token0: route.pool_key.token0.toBigInt(),
|
|
866
|
-
token1: route.pool_key.token1.toBigInt(),
|
|
867
|
-
fee: route.pool_key.fee,
|
|
868
|
-
tick_spacing: route.pool_key.tick_spacing,
|
|
869
|
-
extension: ContractAddr.from(route.pool_key.extension).toBigInt(),
|
|
1242
|
+
amount: swap.token_amount.amount.toI129(),
|
|
870
1243
|
},
|
|
871
|
-
sqrt_ratio_limit: uint256.bnToUint256(route.sqrt_ratio_limit.toWei()),
|
|
872
|
-
skip_ahead: BigInt(route.skip_ahead.toWei())
|
|
873
1244
|
})),
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
}
|
|
883
|
-
}
|
|
1245
|
+
withdraw_swap_limit_amount: BigInt(
|
|
1246
|
+
_params.withdraw_swap_limit_amount.toWei()
|
|
1247
|
+
),
|
|
1248
|
+
withdraw_swap_weights: _params.withdraw_swap_weights.map((weight) =>
|
|
1249
|
+
BigInt(weight.toWei())
|
|
1250
|
+
),
|
|
1251
|
+
close_position: _params.close_position,
|
|
1252
|
+
},
|
|
1253
|
+
}),
|
|
1254
|
+
};
|
|
884
1255
|
}
|
|
885
1256
|
|
|
886
1257
|
async getHealthFactor(): Promise<number> {
|
|
@@ -890,15 +1261,19 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
890
1261
|
|
|
891
1262
|
async getNetAPY(): Promise<number> {
|
|
892
1263
|
const positions = await this.getPositions();
|
|
893
|
-
logger.verbose(
|
|
894
|
-
|
|
1264
|
+
logger.verbose(
|
|
1265
|
+
`${this.name}::getNetAPY: positions: ${JSON.stringify(positions)}`
|
|
1266
|
+
);
|
|
1267
|
+
const allZero = positions.every((p) => p.usdValue === 0);
|
|
895
1268
|
|
|
896
1269
|
// in case of zero positions, apy will come zero/NaN
|
|
897
1270
|
// bcz of net 0 zero weights
|
|
898
1271
|
if (allZero) {
|
|
899
1272
|
// use approx dummy usd values to compute netAPY
|
|
900
1273
|
const collateralUSD = 1000;
|
|
901
|
-
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
1274
|
+
const maxLTV = await this.vesuAdapter.getLTVConfig(
|
|
1275
|
+
this.config.networkConfig
|
|
1276
|
+
);
|
|
902
1277
|
const targetHF = this.config.targetHealthFactor;
|
|
903
1278
|
const maxDebt = HealthFactorMath.getMaxDebtAmountOnLooping(
|
|
904
1279
|
new Web3Number(collateralUSD, this.config.collateral.decimals),
|
|
@@ -907,17 +1282,22 @@ export class VesuMultiplyAdapter extends BaseAdapter<DepositParams, WithdrawPara
|
|
|
907
1282
|
targetHF,
|
|
908
1283
|
1, // assume price 1 for simplicity
|
|
909
1284
|
this.config.debt
|
|
910
|
-
)
|
|
1285
|
+
);
|
|
911
1286
|
|
|
912
1287
|
// debt is also added to collateral bcz, we assume debt is swapped to collateral
|
|
913
1288
|
const debtUSD = maxDebt.multipliedBy(1); // assume price 1 for simplicity
|
|
914
|
-
const netAPY =
|
|
1289
|
+
const netAPY =
|
|
1290
|
+
(positions[0].apy.apy * (collateralUSD + debtUSD.toNumber()) +
|
|
1291
|
+
positions[1].apy.apy * debtUSD.toNumber()) /
|
|
1292
|
+
collateralUSD;
|
|
915
1293
|
return netAPY;
|
|
916
1294
|
}
|
|
917
1295
|
|
|
918
1296
|
// Return true APY
|
|
919
1297
|
const netAmount = positions.reduce((acc, curr) => acc + curr.usdValue, 0);
|
|
920
|
-
const netAPY =
|
|
1298
|
+
const netAPY =
|
|
1299
|
+
positions.reduce((acc, curr) => acc + curr.apy.apy * curr.usdValue, 0) /
|
|
1300
|
+
netAmount;
|
|
921
1301
|
logger.verbose(`${this.name}::getNetAPY: netAPY: ${netAPY}`);
|
|
922
1302
|
return netAPY;
|
|
923
1303
|
}
|