@strkfarm/sdk 1.1.69 → 2.0.0-dev.1
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/cli.js +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/index.browser.global.js +66861 -59746
- package/dist/index.browser.mjs +24970 -18579
- package/dist/index.d.ts +1969 -776
- package/dist/index.js +25259 -18845
- package/dist/index.mjs +25464 -19090
- package/package.json +80 -76
- package/src/data/extended-deposit.abi.json +3613 -0
- package/src/data/universal-vault.abi.json +135 -20
- package/src/dataTypes/address.ts +8 -1
- package/src/global.ts +240 -193
- package/src/interfaces/common.tsx +26 -2
- package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
- package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +395 -0
- package/src/modules/avnu.ts +17 -4
- package/src/modules/ekubo-quoter.ts +99 -11
- package/src/modules/erc20.ts +67 -21
- package/src/modules/harvests.ts +16 -29
- package/src/modules/index.ts +5 -1
- package/src/modules/lst-apr.ts +36 -0
- package/src/modules/midas.ts +159 -0
- package/src/modules/pricer-from-api.ts +2 -2
- package/src/modules/pricer.ts +3 -38
- package/src/modules/token-market-data.ts +202 -0
- package/src/node/deployer.ts +1 -36
- package/src/strategies/autoCompounderStrk.ts +1 -1
- package/src/strategies/base-strategy.ts +20 -3
- package/src/strategies/ekubo-cl-vault.tsx +123 -306
- package/src/strategies/index.ts +4 -1
- package/src/strategies/svk-strategy.ts +247 -0
- package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
- package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +418 -0
- package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
- package/src/strategies/universal-adapters/common-adapter.ts +98 -77
- package/src/strategies/universal-adapters/extended-adapter.ts +544 -0
- package/src/strategies/universal-adapters/index.ts +5 -1
- package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
- package/src/strategies/universal-adapters/vesu-adapter.ts +220 -218
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +924 -0
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
- package/src/strategies/universal-lst-muliplier-strategy.tsx +707 -774
- package/src/strategies/universal-strategy.tsx +1098 -1180
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +28 -0
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +48 -0
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +374 -0
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +992 -0
- package/src/strategies/vesu-rebalance.tsx +16 -19
- package/src/utils/health-factor-math.ts +11 -5
|
@@ -7,11 +7,11 @@ import { VesuRebalanceSettings } from "./vesu-rebalance";
|
|
|
7
7
|
import { assert, LeafData, logger, StandardMerkleTree } from "@/utils";
|
|
8
8
|
import UniversalVaultAbi from '../data/universal-vault.abi.json';
|
|
9
9
|
import ManagerAbi from '../data/vault-manager.abi.json';
|
|
10
|
-
import { ApproveCallParams, AvnuSwapCallParams, BaseAdapter, CommonAdapter, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall,
|
|
10
|
+
import { ApproveCallParams, AvnuSwapCallParams, BaseAdapter, CommonAdapter, DepositParams, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall, WithdrawParams } from "./universal-adapters";
|
|
11
11
|
import { Global } from "@/global";
|
|
12
12
|
import { AvnuWrapper, ERC20 } from "@/modules";
|
|
13
13
|
import { AVNU_MIDDLEWARE, VESU_SINGLETON } from "./universal-adapters/adapter-utils";
|
|
14
|
-
import {
|
|
14
|
+
import { VesuHarvests } from "@/modules/harvests";
|
|
15
15
|
|
|
16
16
|
export interface UniversalManageCall {
|
|
17
17
|
proofs: string[];
|
|
@@ -24,16 +24,13 @@ export interface UniversalStrategySettings {
|
|
|
24
24
|
manager: ContractAddr,
|
|
25
25
|
vaultAllocator: ContractAddr,
|
|
26
26
|
redeemRequestNFT: ContractAddr,
|
|
27
|
-
aumOracle: ContractAddr,
|
|
28
27
|
|
|
29
28
|
// Individual merkle tree leaves
|
|
30
29
|
leafAdapters: LeafAdapterFn<any>[],
|
|
31
30
|
|
|
32
31
|
// Useful for returning adapter class objects that can compute
|
|
33
32
|
// certain things for us (e.g. positions, hfs)
|
|
34
|
-
adapters: {id: string, adapter: BaseAdapter}[]
|
|
35
|
-
targetHealthFactor: number,
|
|
36
|
-
minHealthFactor: number
|
|
33
|
+
adapters: {id: string, adapter: BaseAdapter<DepositParams, WithdrawParams>}[]
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
export enum AUMTypes {
|
|
@@ -41,787 +38,705 @@ export enum AUMTypes {
|
|
|
41
38
|
DEFISPRING = 'defispring'
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
export class UniversalStrategy<
|
|
45
|
-
|
|
46
|
-
> extends BaseStrategy<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
41
|
+
// export class UniversalStrategy<
|
|
42
|
+
// S extends UniversalStrategySettings
|
|
43
|
+
// > extends BaseStrategy<
|
|
44
|
+
// SingleTokenInfo,
|
|
45
|
+
// SingleActionAmount
|
|
46
|
+
// > {
|
|
47
|
+
|
|
48
|
+
// /** Contract address of the strategy */
|
|
49
|
+
// readonly address: ContractAddr;
|
|
50
|
+
// /** Pricer instance for token price calculations */
|
|
51
|
+
// readonly pricer: PricerBase;
|
|
52
|
+
// /** Metadata containing strategy information */
|
|
53
|
+
// readonly metadata: IStrategyMetadata<S>;
|
|
54
|
+
// /** Contract instance for interacting with the strategy */
|
|
55
|
+
// readonly contract: Contract;
|
|
56
|
+
// readonly managerContract: Contract;
|
|
57
|
+
// merkleTree: StandardMerkleTree | undefined;
|
|
58
|
+
|
|
59
|
+
// constructor(
|
|
60
|
+
// config: IConfig,
|
|
61
|
+
// pricer: PricerBase,
|
|
62
|
+
// metadata: IStrategyMetadata<S>
|
|
63
|
+
// ) {
|
|
64
|
+
// super(config);
|
|
65
|
+
// this.pricer = pricer;
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
// assert(
|
|
68
|
+
// metadata.depositTokens.length === 1,
|
|
69
|
+
// "VesuRebalance only supports 1 deposit token"
|
|
70
|
+
// );
|
|
71
|
+
// this.metadata = metadata;
|
|
72
|
+
// this.address = metadata.address;
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async getVesuAPYs() {
|
|
202
|
-
// get Vesu pools, positions and APYs
|
|
203
|
-
const vesuAdapters = this.getVesuAdapters();
|
|
204
|
-
const allVesuPools = await VesuAdapter.getVesuPools();
|
|
205
|
-
const pools = vesuAdapters.map((vesuAdapter) => {
|
|
206
|
-
return allVesuPools.pools.find(p => vesuAdapter.config.poolId.eqString(num.getHexString(p.id)));
|
|
207
|
-
});
|
|
208
|
-
logger.verbose(`${this.metadata.name}::netAPY: vesu-pools: ${JSON.stringify(pools)}`);
|
|
209
|
-
if (pools.some(p => !p)) {
|
|
210
|
-
throw new Error('Pool not found');
|
|
211
|
-
};
|
|
212
|
-
const positions = await this.getVesuPositions();
|
|
213
|
-
logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
|
|
214
|
-
const baseAPYs: number[] = [];
|
|
215
|
-
const rewardAPYs: number[] = [];
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
for (const [index, pool] of pools.entries()) {
|
|
219
|
-
const vesuAdapter = vesuAdapters[index];
|
|
220
|
-
const collateralAsset = pool.assets.find((a: any) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats!;
|
|
221
|
-
const debtAsset = pool.assets.find((a: any) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats!;
|
|
222
|
-
const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
|
|
223
|
-
|
|
224
|
-
// Use LST APR from Endur API instead of Vesu's lstApr
|
|
225
|
-
const lstAPY = await this.getLSTAPR(vesuAdapter.config.collateral.address);
|
|
226
|
-
logger.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
|
|
227
|
-
|
|
228
|
-
baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
|
|
229
|
-
rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
|
|
230
|
-
}
|
|
231
|
-
logger.verbose(`${this.metadata.name}::netAPY: baseAPYs: ${JSON.stringify(baseAPYs)}`);
|
|
232
|
-
logger.verbose(`${this.metadata.name}::netAPY: rewardAPYs: ${JSON.stringify(rewardAPYs)}`);
|
|
233
|
-
|
|
234
|
-
// Else further compute will fail
|
|
235
|
-
assert(baseAPYs.length == positions.length, 'APYs and positions length mismatch');
|
|
236
|
-
|
|
237
|
-
return {
|
|
238
|
-
baseAPYs,
|
|
239
|
-
rewardAPYs,
|
|
240
|
-
positions
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Calculates the weighted average APY across all pools based on USD value.
|
|
246
|
-
* @returns {Promise<number>} The weighted average APY across all pools
|
|
247
|
-
*/
|
|
248
|
-
async netAPY(): Promise<{ net: number, splits: { apy: number, id: string }[] }> {
|
|
249
|
-
if (this.metadata.isPreview) {
|
|
250
|
-
return { net: 0, splits: [{
|
|
251
|
-
apy: 0, id: 'base'
|
|
252
|
-
}, {
|
|
253
|
-
apy: 0, id: 'defispring'
|
|
254
|
-
}] };
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
|
|
258
|
-
|
|
259
|
-
const unusedBalanceAPY = await this.getUnusedBalanceAPY();
|
|
260
|
-
baseAPYs.push(...[unusedBalanceAPY.apy]);
|
|
261
|
-
rewardAPYs.push(0);
|
|
262
|
-
|
|
263
|
-
// Compute APy using weights
|
|
264
|
-
const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
|
|
265
|
-
weights.push(unusedBalanceAPY.weight);
|
|
266
|
-
|
|
267
|
-
const prevAUM = await this.getPrevAUM();
|
|
268
|
-
const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
269
|
-
const prevAUMUSD = prevAUM.multipliedBy(price.price);
|
|
270
|
-
return this.returnNetAPY(baseAPYs, rewardAPYs, weights, prevAUMUSD);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
protected async returnNetAPY(baseAPYs: number[], rewardAPYs: number[], weights: number[], prevAUMUSD: Web3Number) {
|
|
274
|
-
// If no positions, return 0
|
|
275
|
-
if (weights.every(p => p == 0)) {
|
|
276
|
-
return { net: 0, splits: [{
|
|
277
|
-
apy: 0, id: 'base'
|
|
278
|
-
}, {
|
|
279
|
-
apy: 0, id: 'defispring'
|
|
280
|
-
}]};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const baseAPY = this.computeAPY(baseAPYs, weights, prevAUMUSD);
|
|
284
|
-
const rewardAPY = this.computeAPY(rewardAPYs, weights, prevAUMUSD);
|
|
285
|
-
const netAPY = baseAPY + rewardAPY;
|
|
286
|
-
logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
|
|
287
|
-
return { net: netAPY, splits: [{
|
|
288
|
-
apy: baseAPY, id: 'base'
|
|
289
|
-
}, {
|
|
290
|
-
apy: rewardAPY, id: 'defispring'
|
|
291
|
-
}] };
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
protected async getUnusedBalanceAPY() {
|
|
295
|
-
return {
|
|
296
|
-
apy: 0, weight: 0
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
private computeAPY(apys: number[], weights: number[], currentAUM: Web3Number) {
|
|
301
|
-
assert(apys.length === weights.length, "APYs and weights length mismatch");
|
|
302
|
-
const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
|
|
303
|
-
logger.verbose(`${this.getTag()} computeAPY: apys: ${JSON.stringify(apys)}, weights: ${JSON.stringify(weights)}, weightedSum: ${weightedSum}, currentAUM: ${currentAUM}`);
|
|
304
|
-
return weightedSum / currentAUM.toNumber();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Calculates the total TVL of the strategy.
|
|
309
|
-
* @returns Object containing the total amount in token units and USD value
|
|
310
|
-
*/
|
|
311
|
-
async getTVL() {
|
|
312
|
-
const assets = await this.contract.total_assets();
|
|
313
|
-
const amount = Web3Number.fromWei(
|
|
314
|
-
assets.toString(),
|
|
315
|
-
this.metadata.depositTokens[0].decimals
|
|
316
|
-
);
|
|
317
|
-
let price = await this.pricer.getPrice(
|
|
318
|
-
this.metadata.depositTokens[0].symbol
|
|
319
|
-
);
|
|
320
|
-
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
321
|
-
return {
|
|
322
|
-
tokenInfo: this.asset(),
|
|
323
|
-
amount,
|
|
324
|
-
usdValue
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
async getUnusedBalance(): Promise<SingleTokenInfo> {
|
|
329
|
-
const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
|
|
330
|
-
const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
331
|
-
const usdValue = Number(balance.toFixed(6)) * price.price;
|
|
332
|
-
return {
|
|
333
|
-
tokenInfo: this.asset(),
|
|
334
|
-
amount: balance,
|
|
335
|
-
usdValue
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
protected async getVesuAUM(adapter: VesuAdapter) {
|
|
340
|
-
const legAUM = await adapter.getPositions(this.config);
|
|
341
|
-
const underlying = this.asset();
|
|
342
|
-
let vesuAum = Web3Number.fromWei("0", underlying.decimals);
|
|
74
|
+
// this.contract = new Contract({
|
|
75
|
+
// abi: UniversalVaultAbi,
|
|
76
|
+
// address: this.address.address,
|
|
77
|
+
// providerOrAccount: this.config.provider
|
|
78
|
+
// });
|
|
79
|
+
// this.managerContract = new Contract({
|
|
80
|
+
// abi: ManagerAbi,
|
|
81
|
+
// address: this.metadata.additionalInfo.manager.address,
|
|
82
|
+
// providerOrAccount: this.config.provider
|
|
83
|
+
// });
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
// getAllLeaves() {
|
|
87
|
+
// const leaves = this.metadata.additionalInfo.leafAdapters.map((adapter, index) => {
|
|
88
|
+
// return adapter()
|
|
89
|
+
// });
|
|
90
|
+
// const _leaves: LeafData[] = [];
|
|
91
|
+
// leaves.forEach((_l) => {
|
|
92
|
+
// _leaves.push(..._l.leaves);
|
|
93
|
+
// })
|
|
94
|
+
// return _leaves;
|
|
95
|
+
|
|
96
|
+
// }
|
|
97
|
+
// getMerkleTree() {
|
|
98
|
+
// if (this.merkleTree) return this.merkleTree;
|
|
99
|
+
// const _leaves = this.getAllLeaves();
|
|
100
|
+
|
|
101
|
+
// const standardTree = StandardMerkleTree.of(_leaves);
|
|
102
|
+
// this.merkleTree = standardTree;
|
|
103
|
+
// return standardTree;
|
|
104
|
+
// }
|
|
105
|
+
|
|
106
|
+
// getMerkleRoot() {
|
|
107
|
+
// return this.getMerkleTree().root;
|
|
108
|
+
// }
|
|
109
|
+
|
|
110
|
+
// getAdapter(id: string): BaseAdapter<DepositParams, WithdrawParams> {
|
|
111
|
+
// const adapter = this.metadata.additionalInfo.adapters.find(adapter => adapter.id === id);
|
|
112
|
+
// if (!adapter) {
|
|
113
|
+
// throw new Error(`Adapter not found for ID: ${id}`);
|
|
114
|
+
// }
|
|
115
|
+
// return adapter.adapter;
|
|
116
|
+
// }
|
|
117
|
+
|
|
118
|
+
// asset() {
|
|
119
|
+
// return this.metadata.depositTokens[0];
|
|
120
|
+
// }
|
|
121
|
+
|
|
122
|
+
// async depositCall(amountInfo: SingleActionAmount, receiver: ContractAddr): Promise<Call[]> {
|
|
123
|
+
// // Technically its not erc4626 abi, but we just need approve call
|
|
124
|
+
// // so, its ok to use it
|
|
125
|
+
// assert(
|
|
126
|
+
// amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
127
|
+
// "Deposit token mismatch"
|
|
128
|
+
// );
|
|
129
|
+
// const assetContract = new Contract({
|
|
130
|
+
// abi: UniversalVaultAbi,
|
|
131
|
+
// address: this.asset().address.address,
|
|
132
|
+
// providerOrAccount: this.config.provider
|
|
133
|
+
// });
|
|
134
|
+
// const call1 = assetContract.populate("approve", [
|
|
135
|
+
// this.address.address,
|
|
136
|
+
// uint256.bnToUint256(amountInfo.amount.toWei())
|
|
137
|
+
// ]);
|
|
138
|
+
// const call2 = this.contract.populate("deposit", [
|
|
139
|
+
// uint256.bnToUint256(amountInfo.amount.toWei()),
|
|
140
|
+
// receiver.address
|
|
141
|
+
// ]);
|
|
142
|
+
// return [call1, call2];
|
|
143
|
+
// }
|
|
144
|
+
|
|
145
|
+
// async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
|
|
146
|
+
// assert(
|
|
147
|
+
// amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
148
|
+
// "Withdraw token mismatch"
|
|
149
|
+
// );
|
|
150
|
+
// const shares = await this.contract.call('convert_to_shares', [uint256.bnToUint256(amountInfo.amount.toWei())]);
|
|
151
|
+
// const call = this.contract.populate("request_redeem", [
|
|
152
|
+
// uint256.bnToUint256(shares.toString()),
|
|
153
|
+
// receiver.address,
|
|
154
|
+
// owner.address
|
|
155
|
+
// ]);
|
|
156
|
+
// return [call];
|
|
157
|
+
// }
|
|
158
|
+
|
|
159
|
+
// /**
|
|
160
|
+
// * Calculates the Total Value Locked (TVL) for a specific user.
|
|
161
|
+
// * @param user - Address of the user
|
|
162
|
+
// * @returns Object containing the amount in token units and USD value
|
|
163
|
+
// */
|
|
164
|
+
// async getUserTVL(user: ContractAddr) {
|
|
165
|
+
// const shares = await this.contract.balance_of(user.address);
|
|
166
|
+
// const assets = await this.contract.convert_to_assets(
|
|
167
|
+
// uint256.bnToUint256(shares)
|
|
168
|
+
// );
|
|
169
|
+
// const amount = Web3Number.fromWei(
|
|
170
|
+
// assets.toString(),
|
|
171
|
+
// this.metadata.depositTokens[0].decimals
|
|
172
|
+
// );
|
|
173
|
+
// let price = await this.pricer.getPrice(
|
|
174
|
+
// this.metadata.depositTokens[0].symbol
|
|
175
|
+
// );
|
|
176
|
+
// const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
177
|
+
// return {
|
|
178
|
+
// tokenInfo: this.asset(),
|
|
179
|
+
// amount,
|
|
180
|
+
// usdValue
|
|
181
|
+
// };
|
|
182
|
+
// }
|
|
183
|
+
|
|
184
|
+
// /**
|
|
185
|
+
// * Calculates the weighted average APY across all pools based on USD value.
|
|
186
|
+
// * @returns {Promise<number>} The weighted average APY across all pools
|
|
187
|
+
// */
|
|
188
|
+
// async netAPY(): Promise<{ net: number, splits: { apy: number, id: string }[] }> {
|
|
189
|
+
// if (this.metadata.isPreview) {
|
|
190
|
+
// return { net: 0, splits: [{
|
|
191
|
+
// apy: 0, id: 'base'
|
|
192
|
+
// }, {
|
|
193
|
+
// apy: 0, id: 'defispring'
|
|
194
|
+
// }] };
|
|
195
|
+
// }
|
|
343
196
|
|
|
344
|
-
|
|
345
|
-
|
|
197
|
+
// const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
|
|
198
|
+
|
|
199
|
+
// const unusedBalanceAPY = await this.getUnusedBalanceAPY();
|
|
200
|
+
// baseAPYs.push(...[unusedBalanceAPY.apy]);
|
|
201
|
+
// rewardAPYs.push(0);
|
|
202
|
+
|
|
203
|
+
// // Compute APy using weights
|
|
204
|
+
// const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
|
|
205
|
+
// weights.push(unusedBalanceAPY.weight);
|
|
206
|
+
|
|
207
|
+
// const prevAUM = await this.getPrevAUM();
|
|
208
|
+
// const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
209
|
+
// const prevAUMUSD = prevAUM.multipliedBy(price.price);
|
|
210
|
+
// return this.returnNetAPY(baseAPYs, rewardAPYs, weights, prevAUMUSD);
|
|
211
|
+
// }
|
|
212
|
+
|
|
213
|
+
// protected async returnNetAPY(baseAPYs: number[], rewardAPYs: number[], weights: number[], prevAUMUSD: Web3Number) {
|
|
214
|
+
// // If no positions, return 0
|
|
215
|
+
// if (weights.every(p => p == 0)) {
|
|
216
|
+
// return { net: 0, splits: [{
|
|
217
|
+
// apy: 0, id: 'base'
|
|
218
|
+
// }, {
|
|
219
|
+
// apy: 0, id: 'defispring'
|
|
220
|
+
// }]};
|
|
221
|
+
// }
|
|
222
|
+
|
|
223
|
+
// const baseAPY = this.computeAPY(baseAPYs, weights, prevAUMUSD);
|
|
224
|
+
// const rewardAPY = this.computeAPY(rewardAPYs, weights, prevAUMUSD);
|
|
225
|
+
// const netAPY = baseAPY + rewardAPY;
|
|
226
|
+
// logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
|
|
227
|
+
// return { net: netAPY, splits: [{
|
|
228
|
+
// apy: baseAPY, id: 'base'
|
|
229
|
+
// }, {
|
|
230
|
+
// apy: rewardAPY, id: 'defispring'
|
|
231
|
+
// }] };
|
|
232
|
+
// }
|
|
233
|
+
|
|
234
|
+
// protected async getUnusedBalanceAPY() {
|
|
235
|
+
// return {
|
|
236
|
+
// apy: 0, weight: 0
|
|
237
|
+
// }
|
|
238
|
+
// }
|
|
239
|
+
|
|
240
|
+
// private computeAPY(apys: number[], weights: number[], currentAUM: Web3Number) {
|
|
241
|
+
// assert(apys.length === weights.length, "APYs and weights length mismatch");
|
|
242
|
+
// const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
|
|
243
|
+
// logger.verbose(`${this.getTag()} computeAPY: apys: ${JSON.stringify(apys)}, weights: ${JSON.stringify(weights)}, weightedSum: ${weightedSum}, currentAUM: ${currentAUM}`);
|
|
244
|
+
// return weightedSum / currentAUM.toNumber();
|
|
245
|
+
// }
|
|
246
|
+
|
|
247
|
+
// /**
|
|
248
|
+
// * Calculates the total TVL of the strategy.
|
|
249
|
+
// * @returns Object containing the total amount in token units and USD value
|
|
250
|
+
// */
|
|
251
|
+
// async getTVL() {
|
|
252
|
+
// const assets = await this.contract.total_assets();
|
|
253
|
+
// const amount = Web3Number.fromWei(
|
|
254
|
+
// assets.toString(),
|
|
255
|
+
// this.metadata.depositTokens[0].decimals
|
|
256
|
+
// );
|
|
257
|
+
// let price = await this.pricer.getPrice(
|
|
258
|
+
// this.metadata.depositTokens[0].symbol
|
|
259
|
+
// );
|
|
260
|
+
// const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
261
|
+
// return {
|
|
262
|
+
// tokenInfo: this.asset(),
|
|
263
|
+
// amount,
|
|
264
|
+
// usdValue
|
|
265
|
+
// };
|
|
266
|
+
// }
|
|
267
|
+
|
|
268
|
+
// async getUnusedBalance(): Promise<SingleTokenInfo> {
|
|
269
|
+
// const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
|
|
270
|
+
// const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
271
|
+
// const usdValue = Number(balance.toFixed(6)) * price.price;
|
|
272
|
+
// return {
|
|
273
|
+
// tokenInfo: this.asset(),
|
|
274
|
+
// amount: balance,
|
|
275
|
+
// usdValue
|
|
276
|
+
// };
|
|
277
|
+
// }
|
|
278
|
+
|
|
279
|
+
// protected async getVesuAUM(adapter: VesuAdapter) {
|
|
280
|
+
// const legAUM = await adapter.getPositions(this.config);
|
|
281
|
+
// const underlying = this.asset();
|
|
282
|
+
// let vesuAum = Web3Number.fromWei("0", underlying.decimals);
|
|
346
283
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
vesuAum = vesuAum.plus(legAUM[0].amount);
|
|
350
|
-
} else {
|
|
351
|
-
vesuAum = vesuAum.plus(legAUM[0].usdValue / tokenUnderlyingPrice.price);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// handle debt
|
|
355
|
-
if (legAUM[1].token.address.eq(underlying.address)) {
|
|
356
|
-
vesuAum = vesuAum.minus(legAUM[1].amount);
|
|
357
|
-
} else {
|
|
358
|
-
vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
|
|
362
|
-
return vesuAum;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
async getPrevAUM() {
|
|
366
|
-
const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
|
|
367
|
-
const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
|
|
368
|
-
logger.verbose(`${this.getTag()} Prev AUM: ${prevAum}`);
|
|
369
|
-
return prevAum;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
|
|
373
|
-
const prevAum = await this.getPrevAUM();
|
|
374
|
-
const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
375
|
-
|
|
376
|
-
// calculate vesu aum
|
|
377
|
-
const vesuAdapters = this.getVesuAdapters();
|
|
378
|
-
let vesuAum = Web3Number.fromWei("0", this.asset().decimals);
|
|
379
|
-
for (const adapter of vesuAdapters) {
|
|
380
|
-
vesuAum = vesuAum.plus(await this.getVesuAUM(adapter));
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// account unused balance as aum as well (from vault allocator)
|
|
384
|
-
const balance = await this.getUnusedBalance();
|
|
385
|
-
logger.verbose(`${this.getTag()} unused balance: ${balance.amount.toNumber()}`);
|
|
386
|
-
|
|
387
|
-
// Initiate return values
|
|
388
|
-
const zeroAmt = Web3Number.fromWei('0', this.asset().decimals);
|
|
389
|
-
const net = {
|
|
390
|
-
tokenInfo: this.asset(),
|
|
391
|
-
amount: zeroAmt,
|
|
392
|
-
usdValue: 0
|
|
393
|
-
};
|
|
394
|
-
const aumToken = vesuAum.plus(balance.amount);
|
|
395
|
-
if (aumToken.isZero()) {
|
|
396
|
-
return { net, splits: [{
|
|
397
|
-
aum: zeroAmt, id: AUMTypes.FINALISED
|
|
398
|
-
}, {
|
|
399
|
-
aum: zeroAmt, id: AUMTypes.DEFISPRING
|
|
400
|
-
}], prevAum};
|
|
401
|
-
}
|
|
402
|
-
logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
|
|
403
|
-
|
|
404
|
-
// compute rewards contribution to AUM
|
|
405
|
-
const rewardAssets = await this.getRewardsAUM(prevAum);
|
|
406
|
-
|
|
407
|
-
// Sum up and return
|
|
408
|
-
const newAUM = aumToken.plus(rewardAssets);
|
|
409
|
-
logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
|
|
284
|
+
// let tokenUnderlyingPrice = await this.pricer.getPrice(this.asset().symbol);
|
|
285
|
+
// logger.verbose(`${this.getTag()} tokenUnderlyingPrice: ${tokenUnderlyingPrice.price}`);
|
|
410
286
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
287
|
+
// // handle collateral
|
|
288
|
+
// if (legAUM[0].token.address.eq(underlying.address)) {
|
|
289
|
+
// vesuAum = vesuAum.plus(legAUM[0].amount);
|
|
290
|
+
// } else {
|
|
291
|
+
// vesuAum = vesuAum.plus(legAUM[0].usdValue / tokenUnderlyingPrice.price);
|
|
292
|
+
// }
|
|
293
|
+
|
|
294
|
+
// // handle debt
|
|
295
|
+
// if (legAUM[1].token.address.eq(underlying.address)) {
|
|
296
|
+
// vesuAum = vesuAum.minus(legAUM[1].amount);
|
|
297
|
+
// } else {
|
|
298
|
+
// vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
|
|
299
|
+
// };
|
|
300
|
+
|
|
301
|
+
// logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
|
|
302
|
+
// return vesuAum;
|
|
303
|
+
// }
|
|
304
|
+
|
|
305
|
+
// async getPrevAUM() {
|
|
306
|
+
// const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
|
|
307
|
+
// const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
|
|
308
|
+
// logger.verbose(`${this.getTag()} Prev AUM: ${prevAum}`);
|
|
309
|
+
// return prevAum;
|
|
310
|
+
// }
|
|
311
|
+
|
|
312
|
+
// async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
|
|
313
|
+
// const prevAum = await this.getPrevAUM();
|
|
314
|
+
// const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
315
|
+
|
|
316
|
+
// // calculate vesu aum
|
|
317
|
+
// const vesuAdapters = this.getVesuAdapters();
|
|
318
|
+
// let vesuAum = Web3Number.fromWei("0", this.asset().decimals);
|
|
319
|
+
// for (const adapter of vesuAdapters) {
|
|
320
|
+
// vesuAum = vesuAum.plus(await this.getVesuAUM(adapter));
|
|
321
|
+
// }
|
|
322
|
+
|
|
323
|
+
// // account unused balance as aum as well (from vault allocator)
|
|
324
|
+
// const balance = await this.getUnusedBalance();
|
|
325
|
+
// logger.verbose(`${this.getTag()} unused balance: ${balance.amount.toNumber()}`);
|
|
326
|
+
|
|
327
|
+
// // Initiate return values
|
|
328
|
+
// const zeroAmt = Web3Number.fromWei('0', this.asset().decimals);
|
|
329
|
+
// const net = {
|
|
330
|
+
// tokenInfo: this.asset(),
|
|
331
|
+
// amount: zeroAmt,
|
|
332
|
+
// usdValue: 0
|
|
333
|
+
// };
|
|
334
|
+
// const aumToken = vesuAum.plus(balance.amount);
|
|
335
|
+
// if (aumToken.isZero()) {
|
|
336
|
+
// return { net, splits: [{
|
|
337
|
+
// aum: zeroAmt, id: AUMTypes.FINALISED
|
|
338
|
+
// }, {
|
|
339
|
+
// aum: zeroAmt, id: AUMTypes.DEFISPRING
|
|
340
|
+
// }], prevAum};
|
|
341
|
+
// }
|
|
342
|
+
// logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
|
|
343
|
+
|
|
344
|
+
// // compute rewards contribution to AUM
|
|
345
|
+
// const rewardAssets = await this.getRewardsAUM(prevAum);
|
|
346
|
+
|
|
347
|
+
// // Sum up and return
|
|
348
|
+
// const newAUM = aumToken.plus(rewardAssets);
|
|
349
|
+
// logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
|
|
451
350
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
351
|
+
// net.amount = newAUM;
|
|
352
|
+
// net.usdValue = newAUM.multipliedBy(token1Price.price).toNumber();
|
|
353
|
+
// const splits = [{
|
|
354
|
+
// id: AUMTypes.FINALISED,
|
|
355
|
+
// aum: aumToken
|
|
356
|
+
// }, {
|
|
357
|
+
// id: AUMTypes.DEFISPRING,
|
|
358
|
+
// aum: rewardAssets
|
|
359
|
+
// }];
|
|
360
|
+
// return { net, splits, prevAum };
|
|
361
|
+
// }
|
|
362
|
+
|
|
363
|
+
// // account for future rewards (e.g. defispring rewards)
|
|
364
|
+
// protected async getRewardsAUM(prevAum: Web3Number) {
|
|
365
|
+
// const lastReportTime = await this.contract.call('last_report_timestamp', []);
|
|
366
|
+
// // - calculate estimated growth from strk rewards
|
|
367
|
+
// const netAPY = await this.netAPY();
|
|
368
|
+
// // account only 80% of value
|
|
369
|
+
// const defispringAPY = (netAPY.splits.find(s => s.id === 'defispring')?.apy || 0) * 0.8;
|
|
370
|
+
// if (!defispringAPY) throw new Error('DefiSpring APY not found');
|
|
371
|
+
|
|
372
|
+
// // compute rewards contribution to AUM
|
|
373
|
+
// const timeDiff = (Math.round(Date.now() / 1000) - Number(lastReportTime));
|
|
374
|
+
// const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
|
|
375
|
+
// const rewardAssets = prevAum.multipliedBy(growthRate);
|
|
376
|
+
// logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
|
|
377
|
+
// logger.verbose(`${this.getTag()} Current AUM: ${prevAum.toString()}`);
|
|
378
|
+
// logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
|
|
379
|
+
// logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
|
|
380
|
+
|
|
381
|
+
// return rewardAssets;
|
|
382
|
+
// }
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
// async getVaultPositions(): Promise<VaultPosition[]> {
|
|
387
|
+
// const vesuPositions = await this.getVesuPositions();
|
|
388
|
+
// const unusedBalance = await this.getUnusedBalance();
|
|
389
|
+
// return [...vesuPositions, {
|
|
390
|
+
// amount: unusedBalance.amount,
|
|
391
|
+
// usdValue: unusedBalance.usdValue,
|
|
392
|
+
// token: this.asset(),
|
|
393
|
+
// remarks: "Unused Balance (may not include recent deposits)"
|
|
394
|
+
// }];
|
|
395
|
+
// }
|
|
396
|
+
|
|
397
|
+
// getSetManagerCall(strategist: ContractAddr, root = this.getMerkleRoot()) {
|
|
398
|
+
// return this.managerContract.populate('set_manage_root', [strategist.address, num.getHexString(root)]);
|
|
399
|
+
// }
|
|
478
400
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
401
|
+
// getManageCall(proofIds: string[], manageCalls: ManageCall[]) {
|
|
402
|
+
// assert(proofIds.length == manageCalls.length, 'Proof IDs and Manage Calls length mismatch');
|
|
403
|
+
// return this.managerContract.populate('manage_vault_with_merkle_verification', {
|
|
404
|
+
// proofs: proofIds.map(id => this.getProofs(id).proofs),
|
|
405
|
+
// decoder_and_sanitizers: manageCalls.map(call => call.sanitizer.address),
|
|
406
|
+
// targets: manageCalls.map(call => call.call.contractAddress.address),
|
|
407
|
+
// selectors: manageCalls.map(call => call.call.selector),
|
|
408
|
+
// calldatas: manageCalls.map(call => call.call.calldata), // Calldata[]
|
|
409
|
+
// });
|
|
410
|
+
// }
|
|
489
411
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
412
|
+
// getVesuModifyPositionCalls(params: {
|
|
413
|
+
// isLeg1: boolean,
|
|
414
|
+
// isDeposit: boolean,
|
|
415
|
+
// depositAmount: Web3Number,
|
|
416
|
+
// debtAmount: Web3Number
|
|
417
|
+
// }): UniversalManageCall[] {
|
|
418
|
+
// assert(params.depositAmount.gt(0) || params.debtAmount.gt(0), 'Either deposit or debt amount must be greater than 0');
|
|
419
|
+
// // approve token
|
|
420
|
+
// const isToken1 = params.isLeg1 == params.isDeposit; // XOR
|
|
421
|
+
// const STEP1_ID = isToken1 ? UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1 :UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2;
|
|
422
|
+
// const manage4Info = this.getProofs<ApproveCallParams>(STEP1_ID);
|
|
423
|
+
// const approveAmount = params.isDeposit ? params.depositAmount : params.debtAmount;
|
|
424
|
+
// const manageCall4 = manage4Info.callConstructor({
|
|
425
|
+
// amount: approveAmount
|
|
426
|
+
// })
|
|
427
|
+
|
|
428
|
+
// // deposit and borrow or repay and withdraw
|
|
429
|
+
// const STEP2_ID = params.isLeg1 ? UNIVERSAL_MANAGE_IDS.VESU_LEG1 : UNIVERSAL_MANAGE_IDS.VESU_LEG2;
|
|
430
|
+
// const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP2_ID);
|
|
431
|
+
// const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
432
|
+
// collateralAmount: params.depositAmount,
|
|
433
|
+
// isAddCollateral: params.isDeposit,
|
|
434
|
+
// debtAmount: params.debtAmount,
|
|
435
|
+
// isBorrow: params.isDeposit
|
|
436
|
+
// }))
|
|
437
|
+
|
|
438
|
+
// const output = [{
|
|
439
|
+
// proofs: manage5Info.proofs,
|
|
440
|
+
// manageCall: manageCall5,
|
|
441
|
+
// step: STEP2_ID
|
|
442
|
+
// }];
|
|
443
|
+
// if (approveAmount.gt(0)) {
|
|
444
|
+
// output.unshift({
|
|
445
|
+
// proofs: manage4Info.proofs,
|
|
446
|
+
// manageCall: manageCall4,
|
|
447
|
+
// step: STEP1_ID
|
|
448
|
+
// })
|
|
449
|
+
// }
|
|
450
|
+
// return output;
|
|
451
|
+
// }
|
|
452
|
+
|
|
453
|
+
// getTag() {
|
|
454
|
+
// return `${UniversalStrategy.name}:${this.metadata.name}`;
|
|
455
|
+
// }
|
|
456
|
+
|
|
457
|
+
// /**
|
|
458
|
+
// * Gets LST APR for the strategy's underlying asset from Endur API
|
|
459
|
+
// * @returns Promise<number> The LST APR (not divided by 1e18)
|
|
460
|
+
// */
|
|
461
|
+
// async getLSTAPR(address: ContractAddr): Promise<number> {
|
|
462
|
+
// return 0;
|
|
463
|
+
// }
|
|
464
|
+
|
|
465
|
+
// async getVesuHealthFactors(blockNumber: BlockIdentifier = 'latest') {
|
|
466
|
+
// return await Promise.all(this.getVesuAdapters().map(v => v.getHealthFactor(blockNumber)));
|
|
467
|
+
// }
|
|
468
|
+
|
|
469
|
+
// async computeRebalanceConditionAndReturnCalls(): Promise<Call[]> {
|
|
470
|
+
// const vesuAdapters = this.getVesuAdapters();
|
|
471
|
+
// const healthFactors = await this.getVesuHealthFactors();
|
|
472
|
+
// const leg1HealthFactor = healthFactors[0];
|
|
473
|
+
// const leg2HealthFactor = healthFactors[1];
|
|
474
|
+
// logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
|
|
475
|
+
// logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
|
|
476
|
+
|
|
477
|
+
// const minHf = this.metadata.additionalInfo.minHealthFactor;
|
|
478
|
+
// const isRebalanceNeeded1 = leg1HealthFactor < minHf;
|
|
479
|
+
// const isRebalanceNeeded2 = leg2HealthFactor < minHf;
|
|
480
|
+
// if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
|
|
481
|
+
// return [];
|
|
482
|
+
// }
|
|
561
483
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
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
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
const manageCall = this.getManageCall([
|
|
819
|
-
...callSet2.map(i => i.step), ...callSet1.map(i => i.step)
|
|
820
|
-
], [...callSet2.map(i => i.manageCall), ...callSet1.map(i => i.manageCall)]);
|
|
821
|
-
return manageCall;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
}
|
|
484
|
+
// if (isRebalanceNeeded1) {
|
|
485
|
+
// const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
|
|
486
|
+
// const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
|
|
487
|
+
// assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
|
|
488
|
+
// return [await this.getRebalanceCall({
|
|
489
|
+
// isLeg1toLeg2: false,
|
|
490
|
+
// amount: amount
|
|
491
|
+
// })];
|
|
492
|
+
// } else {
|
|
493
|
+
// const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
|
|
494
|
+
// const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
|
|
495
|
+
// assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
|
|
496
|
+
// return [await this.getRebalanceCall({
|
|
497
|
+
// isLeg1toLeg2: true,
|
|
498
|
+
// amount: amount
|
|
499
|
+
// })];
|
|
500
|
+
// }
|
|
501
|
+
// }
|
|
502
|
+
|
|
503
|
+
// private async getNewHealthFactor(vesuAdapter: VesuAdapter, newAmount: Web3Number, isWithdraw: boolean) {
|
|
504
|
+
// const {
|
|
505
|
+
// collateralTokenAmount,
|
|
506
|
+
// collateralUSDAmount,
|
|
507
|
+
// collateralPrice,
|
|
508
|
+
// debtTokenAmount,
|
|
509
|
+
// debtUSDAmount,
|
|
510
|
+
// debtPrice,
|
|
511
|
+
// ltv
|
|
512
|
+
// } = await vesuAdapter.getAssetPrices();
|
|
513
|
+
|
|
514
|
+
// if (isWithdraw) {
|
|
515
|
+
// const newHF = ((collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv) / debtUSDAmount;
|
|
516
|
+
// logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
|
|
517
|
+
// return newHF;
|
|
518
|
+
// } else { // is borrow
|
|
519
|
+
// const newHF = (collateralUSDAmount * ltv) / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
|
|
520
|
+
// logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
|
|
521
|
+
// return newHF;
|
|
522
|
+
// }
|
|
523
|
+
// }
|
|
524
|
+
|
|
525
|
+
// /**
|
|
526
|
+
// *
|
|
527
|
+
// * @param vesuAdapter
|
|
528
|
+
// * @param currentHf
|
|
529
|
+
// * @param isDeposit if true, attempt by adding collateral, else by repaying
|
|
530
|
+
// * @returns
|
|
531
|
+
// */
|
|
532
|
+
// private async getLegRebalanceAmount(vesuAdapter: VesuAdapter, currentHf: number, isDeposit: boolean) {
|
|
533
|
+
// const {
|
|
534
|
+
// collateralTokenAmount,
|
|
535
|
+
// collateralUSDAmount,
|
|
536
|
+
// collateralPrice,
|
|
537
|
+
// debtTokenAmount,
|
|
538
|
+
// debtUSDAmount,
|
|
539
|
+
// debtPrice,
|
|
540
|
+
// ltv
|
|
541
|
+
// } = await vesuAdapter.getAssetPrices();
|
|
542
|
+
|
|
543
|
+
// // debt is zero, nothing to rebalance
|
|
544
|
+
// if(debtTokenAmount.isZero()) {
|
|
545
|
+
// return Web3Number.fromWei(0, 0);
|
|
546
|
+
// }
|
|
547
|
+
|
|
548
|
+
// assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
|
|
549
|
+
|
|
550
|
+
// // avoid calculating for too close
|
|
551
|
+
// const targetHF = this.metadata.additionalInfo.targetHealthFactor;
|
|
552
|
+
// if (currentHf > targetHF - 0.01)
|
|
553
|
+
// throw new Error("getLegRebalanceAmount: Current health factor is healthy");
|
|
554
|
+
|
|
555
|
+
// if (isDeposit) {
|
|
556
|
+
// // TargetHF = (collAmount + newAmount) * price * ltv / debtUSD
|
|
557
|
+
// const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
|
|
558
|
+
// logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: addCollateral, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
|
|
559
|
+
// return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
|
|
560
|
+
// } else {
|
|
561
|
+
// // TargetHF = collUSD * ltv / (debtAmount - newAmount) * debtPrice
|
|
562
|
+
// const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
|
|
563
|
+
// logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: repayDebt, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
|
|
564
|
+
// return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
|
|
565
|
+
// }
|
|
566
|
+
// }
|
|
567
|
+
|
|
568
|
+
// async getVesuModifyPositionCall(params: {
|
|
569
|
+
// isDeposit: boolean,
|
|
570
|
+
// leg1DepositAmount: Web3Number
|
|
571
|
+
// }) {
|
|
572
|
+
// const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
|
|
573
|
+
// const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
574
|
+
// const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
|
|
575
|
+
// logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
|
|
576
|
+
// logger.verbose(`${this.getTag()}: LTVLeg2: ${leg2LTV}`);
|
|
577
|
+
|
|
578
|
+
// const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
|
|
579
|
+
// const token2Price = await this.pricer.getPrice(vesuAdapter2.config.collateral.symbol);
|
|
580
|
+
// logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
|
|
581
|
+
// logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
|
|
582
|
+
|
|
583
|
+
// const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
|
|
584
|
+
|
|
585
|
+
// const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
|
|
586
|
+
// const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
|
|
587
|
+
|
|
588
|
+
// const borrow2Amount = new Web3Number(
|
|
589
|
+
// params.leg1DepositAmount.multipliedBy(k1.toFixed(6)).dividedBy(k2 - k1).toFixed(6),
|
|
590
|
+
// vesuAdapter2.config.debt.decimals
|
|
591
|
+
// );
|
|
592
|
+
// const borrow1Amount = new Web3Number(
|
|
593
|
+
// borrow2Amount.multipliedBy(k2).toFixed(6),
|
|
594
|
+
// vesuAdapter1.config.debt.decimals
|
|
595
|
+
// );
|
|
596
|
+
// logger.verbose(`${this.getTag()}:: leg1DepositAmount: ${params.leg1DepositAmount.toString()} ${vesuAdapter1.config.collateral.symbol}`);
|
|
597
|
+
// logger.verbose(`${this.getTag()}:: borrow1Amount: ${borrow1Amount.toString()} ${vesuAdapter1.config.debt.symbol}`);
|
|
598
|
+
// logger.verbose(`${this.getTag()}:: borrow2Amount: ${borrow2Amount.toString()} ${vesuAdapter2.config.debt.symbol}`);
|
|
599
|
+
|
|
600
|
+
// let callSet1 = this.getVesuModifyPositionCalls({
|
|
601
|
+
// isLeg1: true,
|
|
602
|
+
// isDeposit: params.isDeposit,
|
|
603
|
+
// depositAmount: params.leg1DepositAmount.plus(borrow2Amount),
|
|
604
|
+
// debtAmount: borrow1Amount
|
|
605
|
+
// });
|
|
606
|
+
|
|
607
|
+
// let callSet2 = this.getVesuModifyPositionCalls({
|
|
608
|
+
// isLeg1: false,
|
|
609
|
+
// isDeposit: params.isDeposit,
|
|
610
|
+
// depositAmount: borrow1Amount,
|
|
611
|
+
// debtAmount: borrow2Amount
|
|
612
|
+
// });
|
|
613
|
+
|
|
614
|
+
// if (!params.isDeposit) {
|
|
615
|
+
// let temp = callSet2;
|
|
616
|
+
// callSet2 = [...callSet1];
|
|
617
|
+
// callSet1 = [...temp];
|
|
618
|
+
// }
|
|
619
|
+
// const allActions = [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)];
|
|
620
|
+
// const flashloanCalldata = CallData.compile([
|
|
621
|
+
// [...callSet1.map(i => i.proofs), ...callSet2.map(i => i.proofs)],
|
|
622
|
+
// allActions.map(i => i.sanitizer.address),
|
|
623
|
+
// allActions.map(i => i.call.contractAddress.address),
|
|
624
|
+
// allActions.map(i => i.call.selector),
|
|
625
|
+
// allActions.map(i => i.call.calldata)
|
|
626
|
+
// ])
|
|
627
|
+
|
|
628
|
+
// // flash loan
|
|
629
|
+
// const STEP1_ID = UNIVERSAL_MANAGE_IDS.FLASH_LOAN;
|
|
630
|
+
// const manage1Info = this.getProofs<FlashloanCallParams>(STEP1_ID);
|
|
631
|
+
// const manageCall1 = manage1Info.callConstructor({
|
|
632
|
+
// amount: borrow2Amount,
|
|
633
|
+
// data: flashloanCalldata.map(i => BigInt(i))
|
|
634
|
+
// })
|
|
635
|
+
// const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.FLASH_LOAN], [manageCall1]);
|
|
636
|
+
// return manageCall;
|
|
637
|
+
// }
|
|
638
|
+
|
|
639
|
+
// async getBringLiquidityCall(params: {
|
|
640
|
+
// amount: Web3Number
|
|
641
|
+
// }) {
|
|
642
|
+
// const manage1Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY);
|
|
643
|
+
// const manageCall1 = manage1Info.callConstructor({
|
|
644
|
+
// amount: params.amount
|
|
645
|
+
// });
|
|
646
|
+
// const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY);
|
|
647
|
+
// const manageCall2 = manage2Info.callConstructor({
|
|
648
|
+
// amount: params.amount
|
|
649
|
+
// });
|
|
650
|
+
// const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY, UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY], [manageCall1, manageCall2]);
|
|
651
|
+
// return manageCall;
|
|
652
|
+
// }
|
|
653
|
+
|
|
654
|
+
// async getHarvestCall() {
|
|
655
|
+
// const vesuHarvest = new VesuHarvests(this.config);
|
|
656
|
+
// const harvestInfo = await vesuHarvest.getUnHarvestedRewards(this.metadata.additionalInfo.vaultAllocator);
|
|
657
|
+
// if (harvestInfo.length != 1) {
|
|
658
|
+
// throw new Error(`Expected 1 harvest info, got ${harvestInfo.length}`);
|
|
659
|
+
// }
|
|
660
|
+
|
|
661
|
+
// const amount = harvestInfo[0].claim.amount;
|
|
662
|
+
// const actualReward = harvestInfo[0].actualReward;
|
|
663
|
+
// const proofs = harvestInfo[0].proof;
|
|
664
|
+
// if (actualReward.isZero()) {
|
|
665
|
+
// throw new Error(`Expected non-zero actual reward, got ${harvestInfo[0].actualReward}`);
|
|
666
|
+
// }
|
|
667
|
+
|
|
668
|
+
// const manage1Info = this.getProofs<VesuDefiSpringRewardsCallParams>(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS);
|
|
669
|
+
// const manageCall1 = manage1Info.callConstructor({
|
|
670
|
+
// amount,
|
|
671
|
+
// proofs
|
|
672
|
+
// });
|
|
673
|
+
// const proofIds: string[] = [UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS];
|
|
674
|
+
// const manageCalls: ManageCall[] = [manageCall1];
|
|
675
|
+
|
|
676
|
+
// // swap rewards for underlying
|
|
677
|
+
// const STRK = Global.getDefaultTokens().find(t => t.symbol === 'STRK')!;
|
|
678
|
+
// if (this.asset().symbol != 'STRK') {
|
|
679
|
+
// // approve
|
|
680
|
+
// const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
|
|
681
|
+
// const manageCall2 = manage2Info.callConstructor({
|
|
682
|
+
// amount: actualReward
|
|
683
|
+
// });
|
|
684
|
+
|
|
685
|
+
// // swap
|
|
686
|
+
// const avnuModule = new AvnuWrapper();
|
|
687
|
+
// const quote = await avnuModule.getQuotes(
|
|
688
|
+
// STRK.address.address,
|
|
689
|
+
// this.asset().address.address,
|
|
690
|
+
// actualReward.toWei(),
|
|
691
|
+
// this.address.address
|
|
692
|
+
// );
|
|
693
|
+
// const swapInfo = await avnuModule.getSwapInfo(quote, this.address.address, 0, this.address.address);
|
|
694
|
+
// const manage3Info = this.getProofs<AvnuSwapCallParams>(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
|
|
695
|
+
// const manageCall3 = manage3Info.callConstructor({
|
|
696
|
+
// props: swapInfo
|
|
697
|
+
// });
|
|
698
|
+
// proofIds.push(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
|
|
699
|
+
// proofIds.push(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
|
|
700
|
+
|
|
701
|
+
// manageCalls.push(manageCall2);
|
|
702
|
+
// manageCalls.push(manageCall3);
|
|
703
|
+
// }
|
|
704
|
+
|
|
705
|
+
// const manageCall = this.getManageCall(proofIds, manageCalls);
|
|
706
|
+
// return { call: manageCall, reward: actualReward, tokenInfo: STRK };
|
|
707
|
+
// }
|
|
708
|
+
|
|
709
|
+
// async getRebalanceCall(params: {
|
|
710
|
+
// isLeg1toLeg2: boolean,
|
|
711
|
+
// amount: Web3Number
|
|
712
|
+
// }) {
|
|
713
|
+
// let callSet1 = this.getVesuModifyPositionCalls({
|
|
714
|
+
// isLeg1: true,
|
|
715
|
+
// isDeposit: params.isLeg1toLeg2,
|
|
716
|
+
// depositAmount: Web3Number.fromWei(0, 0),
|
|
717
|
+
// debtAmount: params.amount
|
|
718
|
+
// });
|
|
719
|
+
|
|
720
|
+
// let callSet2 = this.getVesuModifyPositionCalls({
|
|
721
|
+
// isLeg1: false,
|
|
722
|
+
// isDeposit: params.isLeg1toLeg2,
|
|
723
|
+
// depositAmount: params.amount,
|
|
724
|
+
// debtAmount: Web3Number.fromWei(0, 0)
|
|
725
|
+
// });
|
|
726
|
+
|
|
727
|
+
// if (params.isLeg1toLeg2) {
|
|
728
|
+
// const manageCall = this.getManageCall([
|
|
729
|
+
// ...callSet1.map(i => i.step), ...callSet2.map(i => i.step)
|
|
730
|
+
// ], [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)]);
|
|
731
|
+
// return manageCall;
|
|
732
|
+
// } else {
|
|
733
|
+
// const manageCall = this.getManageCall([
|
|
734
|
+
// ...callSet2.map(i => i.step), ...callSet1.map(i => i.step)
|
|
735
|
+
// ], [...callSet2.map(i => i.manageCall), ...callSet1.map(i => i.manageCall)]);
|
|
736
|
+
// return manageCall;
|
|
737
|
+
// }
|
|
738
|
+
// }
|
|
739
|
+
// }
|
|
825
740
|
|
|
826
741
|
|
|
827
742
|
// useful to map readble names to proofs and calls
|
|
@@ -842,414 +757,417 @@ export enum UNIVERSAL_MANAGE_IDS {
|
|
|
842
757
|
AVNU_SWAP_REWARDS = 'avnu_swap_rewards'
|
|
843
758
|
}
|
|
844
759
|
|
|
845
|
-
export enum UNIVERSAL_ADAPTERS {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
function getLooperSettings(
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
) {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
760
|
+
// export enum UNIVERSAL_ADAPTERS {
|
|
761
|
+
// COMMON = 'common_adapter',
|
|
762
|
+
// VESU_LEG1 = 'vesu_leg1_adapter',
|
|
763
|
+
// VESU_LEG2 = 'vesu_leg2_adapter'
|
|
764
|
+
// }
|
|
765
|
+
|
|
766
|
+
// function getLooperSettings(
|
|
767
|
+
// token1Symbol: string,
|
|
768
|
+
// token2Symbol: string,
|
|
769
|
+
// vaultSettings: UniversalStrategySettings,
|
|
770
|
+
// pool1: ContractAddr,
|
|
771
|
+
// pool2: ContractAddr,
|
|
772
|
+
// ) {
|
|
773
|
+
// const USDCToken = Global.getDefaultTokens().find(token => token.symbol === token1Symbol)!;
|
|
774
|
+
// const ETHToken = Global.getDefaultTokens().find(token => token.symbol === token2Symbol)!;
|
|
775
|
+
|
|
776
|
+
// const commonAdapter = new CommonAdapter({
|
|
777
|
+
// manager: vaultSettings.manager,
|
|
778
|
+
// asset: USDCToken.address,
|
|
779
|
+
// id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
|
|
780
|
+
// vaultAddress: vaultSettings.vaultAddress,
|
|
781
|
+
// vaultAllocator: vaultSettings.vaultAllocator,
|
|
782
|
+
// })
|
|
783
|
+
// const vesuAdapterUSDCETH = new VesuAdapter({
|
|
784
|
+
// poolId: pool1,
|
|
785
|
+
// collateral: USDCToken,
|
|
786
|
+
// debt: ETHToken,
|
|
787
|
+
// vaultAllocator: vaultSettings.vaultAllocator,
|
|
788
|
+
// id: UNIVERSAL_MANAGE_IDS.VESU_LEG1
|
|
789
|
+
// })
|
|
790
|
+
// const vesuAdapterETHUSDC = new VesuAdapter({
|
|
791
|
+
// poolId: pool2,
|
|
792
|
+
// collateral: ETHToken,
|
|
793
|
+
// debt: USDCToken,
|
|
794
|
+
// vaultAllocator: vaultSettings.vaultAllocator,
|
|
795
|
+
// id: UNIVERSAL_MANAGE_IDS.VESU_LEG2
|
|
796
|
+
// })
|
|
797
|
+
// vaultSettings.adapters.push(...[{
|
|
798
|
+
// id: UNIVERSAL_ADAPTERS.COMMON,
|
|
799
|
+
// adapter: commonAdapter
|
|
800
|
+
// }, {
|
|
801
|
+
// id: UNIVERSAL_ADAPTERS.VESU_LEG1,
|
|
802
|
+
// adapter: vesuAdapterUSDCETH
|
|
803
|
+
// }, {
|
|
804
|
+
// id: UNIVERSAL_ADAPTERS.VESU_LEG2,
|
|
805
|
+
// adapter: vesuAdapterETHUSDC
|
|
806
|
+
// }])
|
|
807
|
+
|
|
808
|
+
// // vesu looping
|
|
809
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getFlashloanAdapter.bind(commonAdapter));
|
|
810
|
+
// vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getModifyPosition.bind(vesuAdapterUSDCETH));
|
|
811
|
+
// vaultSettings.leafAdapters.push(vesuAdapterETHUSDC.getModifyPosition.bind(vesuAdapterETHUSDC));
|
|
812
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
|
|
813
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(ETHToken.address, VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2).bind(commonAdapter));
|
|
899
814
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
815
|
+
// // to bridge liquidity back to vault (used by bring_liquidity)
|
|
816
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
|
|
817
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
|
|
903
818
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
const _riskFactor: RiskFactor[] = [
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
];
|
|
919
|
-
|
|
920
|
-
const usdcVaultSettings: UniversalStrategySettings = {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
const wbtcVaultSettings: UniversalStrategySettings = {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
const ethVaultSettings: UniversalStrategySettings = {
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
const strkVaultSettings: UniversalStrategySettings = {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
const usdtVaultSettings: UniversalStrategySettings = {
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
type AllowedSources = 'vesu' | 'endur' | 'extended';
|
|
981
|
-
export default function MetaVaultDescription(allowedSources: AllowedSources[]) {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
function StatusBadge({ status }: { status: string }) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
function getDescription(tokenSymbol: string, allowedSources: AllowedSources[]) {
|
|
1072
|
-
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
function getFAQs(): FAQ[] {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
export function getContractDetails(settings: UniversalStrategySettings): {address: ContractAddr, name: string}[] {
|
|
1126
|
-
|
|
819
|
+
// // claim rewards
|
|
820
|
+
// vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterUSDCETH));
|
|
821
|
+
|
|
822
|
+
// // avnu swap
|
|
823
|
+
// const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
|
|
824
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_MIDDLEWARE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
|
|
825
|
+
// vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, USDCToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, true).bind(commonAdapter));
|
|
826
|
+
// return vaultSettings;
|
|
827
|
+
// }
|
|
828
|
+
|
|
829
|
+
// const _riskFactor: RiskFactor[] = [
|
|
830
|
+
// { type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25, reason: "Audited by Zellic" },
|
|
831
|
+
// { type: RiskType.LIQUIDATION_RISK, value: 1.5, weight: 50, reason: "Liquidation risk is mitigated by stable price feed on Starknet" },
|
|
832
|
+
// { type: RiskType.TECHNICAL_RISK, value: 1, weight: 50, reason: "Technical failures like risk monitoring failures" }
|
|
833
|
+
// ];
|
|
834
|
+
|
|
835
|
+
// const usdcVaultSettings: UniversalStrategySettings = {
|
|
836
|
+
// vaultAddress: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
|
|
837
|
+
// manager: ContractAddr.from('0xf41a2b1f498a7f9629db0b8519259e66e964260a23d20003f3e42bb1997a07'),
|
|
838
|
+
// vaultAllocator: ContractAddr.from('0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba'),
|
|
839
|
+
// redeemRequestNFT: ContractAddr.from('0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda'),
|
|
840
|
+
// aumOracle: ContractAddr.from("0x6faf45ed185dec13ef723c9ead4266cab98d06f2cb237e331b1fa5c2aa79afe"),
|
|
841
|
+
// leafAdapters: [],
|
|
842
|
+
// adapters: [],
|
|
843
|
+
// targetHealthFactor: 1.3,
|
|
844
|
+
// minHealthFactor: 1.25
|
|
845
|
+
// }
|
|
846
|
+
|
|
847
|
+
// const wbtcVaultSettings: UniversalStrategySettings = {
|
|
848
|
+
// vaultAddress: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
|
|
849
|
+
// manager: ContractAddr.from('0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34'),
|
|
850
|
+
// vaultAllocator: ContractAddr.from('0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735'),
|
|
851
|
+
// redeemRequestNFT: ContractAddr.from('0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2'),
|
|
852
|
+
// aumOracle: ContractAddr.from("0x2edf4edbed3f839e7f07dcd913e92299898ff4cf0ba532f8c572c66c5b331b2"),
|
|
853
|
+
// leafAdapters: [],
|
|
854
|
+
// adapters: [],
|
|
855
|
+
// targetHealthFactor: 1.3,
|
|
856
|
+
// minHealthFactor: 1.25
|
|
857
|
+
// }
|
|
858
|
+
|
|
859
|
+
// const ethVaultSettings: UniversalStrategySettings = {
|
|
860
|
+
// vaultAddress: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
|
|
861
|
+
// manager: ContractAddr.from('0x494888b37206616bd09d759dcda61e5118470b9aa7f58fb84f21c778a7b8f97'),
|
|
862
|
+
// vaultAllocator: ContractAddr.from('0x4acc0ad6bea58cb578d60ff7c31f06f44369a7a9a7bbfffe4701f143e427bd'),
|
|
863
|
+
// redeemRequestNFT: ContractAddr.from('0x2e6cd71e5060a254d4db00655e420db7bf89da7755bb0d5f922e2f00c76ac49'),
|
|
864
|
+
// aumOracle: ContractAddr.from("0x4b747f2e75c057bed9aa2ce46fbdc2159dc684c15bd32d4f95983a6ecf39a05"),
|
|
865
|
+
// leafAdapters: [],
|
|
866
|
+
// adapters: [],
|
|
867
|
+
// targetHealthFactor: 1.3,
|
|
868
|
+
// minHealthFactor: 1.25
|
|
869
|
+
// }
|
|
870
|
+
|
|
871
|
+
// const strkVaultSettings: UniversalStrategySettings = {
|
|
872
|
+
// vaultAddress: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
|
|
873
|
+
// manager: ContractAddr.from('0xcc6a5153ca56293405506eb20826a379d982cd738008ef7e808454d318fb81'),
|
|
874
|
+
// vaultAllocator: ContractAddr.from('0xf29d2f82e896c0ed74c9eff220af34ac148e8b99846d1ace9fbb02c9191d01'),
|
|
875
|
+
// redeemRequestNFT: ContractAddr.from('0x46902423bd632c428376b84fcee9cac5dbe016214e93a8103bcbde6e1de656b'),
|
|
876
|
+
// aumOracle: ContractAddr.from("0x6d7dbfad4bb51715da211468389a623da00c0625f8f6efbea822ee5ac5231f4"),
|
|
877
|
+
// leafAdapters: [],
|
|
878
|
+
// adapters: [],
|
|
879
|
+
// targetHealthFactor: 1.3,
|
|
880
|
+
// minHealthFactor: 1.25
|
|
881
|
+
// }
|
|
882
|
+
|
|
883
|
+
// const usdtVaultSettings: UniversalStrategySettings = {
|
|
884
|
+
// vaultAddress: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
|
|
885
|
+
// manager: ContractAddr.from('0x39bb9843503799b552b7ed84b31c06e4ff10c0537edcddfbf01fe944b864029'),
|
|
886
|
+
// vaultAllocator: ContractAddr.from('0x56437d18c43727ac971f6c7086031cad7d9d6ccb340f4f3785a74cc791c931a'),
|
|
887
|
+
// redeemRequestNFT: ContractAddr.from('0x5af0c2a657eaa8e23ed78e855dac0c51e4f69e2cf91a18c472041a1f75bb41f'),
|
|
888
|
+
// aumOracle: ContractAddr.from("0x7018f8040c8066a4ab929e6760ae52dd43b6a3a289172f514750a61fcc565cc"),
|
|
889
|
+
// leafAdapters: [],
|
|
890
|
+
// adapters: [],
|
|
891
|
+
// targetHealthFactor: 1.3,
|
|
892
|
+
// minHealthFactor: 1.25
|
|
893
|
+
// }
|
|
894
|
+
|
|
895
|
+
// type AllowedSources = 'vesu' | 'endur' | 'extended';
|
|
896
|
+
// export default function MetaVaultDescription(allowedSources: AllowedSources[]) {
|
|
897
|
+
// const logos: any = {
|
|
898
|
+
// vesu: Protocols.VESU.logo,
|
|
899
|
+
// endur: Protocols.ENDUR.logo,
|
|
900
|
+
// extended: Protocols.EXTENDED.logo,
|
|
901
|
+
// ekubo: "https://dummyimage.com/64x64/ffffff/000000&text=K",
|
|
902
|
+
// };
|
|
903
|
+
// const _sources = [
|
|
904
|
+
// { key: "vesu", name: "Vesu", status: "Live", description: "Integrated liquidity venue used for automated routing to capture the best available yield." },
|
|
905
|
+
// { key: "endur", name: "Endur", status: "Coming soon", description: "Planned integration to tap into STRK staking–backed yields via our LST pipeline." },
|
|
906
|
+
// { key: "extended", name: "Extended", status: "Coming soon", description: "Expanding coverage to additional money markets and vaults across the ecosystem." },
|
|
907
|
+
// // { key: "ekubo", name: "Ekubo", status: "Coming soon", description: "Concentrated liquidity strategies targeted for optimized fee APR harvesting." },
|
|
908
|
+
// ];
|
|
909
|
+
// const sources = _sources.filter(s => allowedSources.includes(s.key as any));
|
|
910
|
+
|
|
911
|
+
// const containerStyle = {
|
|
912
|
+
// maxWidth: "800px",
|
|
913
|
+
// margin: "0 auto",
|
|
914
|
+
// backgroundColor: "#111",
|
|
915
|
+
// color: "#eee",
|
|
916
|
+
// fontFamily: "Arial, sans-serif",
|
|
917
|
+
// borderRadius: "12px",
|
|
918
|
+
// };
|
|
919
|
+
|
|
920
|
+
// const cardStyle = {
|
|
921
|
+
// border: "1px solid #333",
|
|
922
|
+
// borderRadius: "10px",
|
|
923
|
+
// padding: "12px",
|
|
924
|
+
// marginBottom: "12px",
|
|
925
|
+
// backgroundColor: "#1a1a1a",
|
|
926
|
+
// };
|
|
927
|
+
|
|
928
|
+
// const logoStyle = {
|
|
929
|
+
// width: "24px",
|
|
930
|
+
// height: "24px",
|
|
931
|
+
// borderRadius: "8px",
|
|
932
|
+
// border: "1px solid #444",
|
|
933
|
+
// backgroundColor: "#222",
|
|
934
|
+
// };
|
|
935
|
+
|
|
936
|
+
// return (
|
|
937
|
+
// <div style={containerStyle}>
|
|
938
|
+
// <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Meta Vault — Automated Yield Router</h1>
|
|
939
|
+
// <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
940
|
+
// This Evergreen vault is a tokenized Meta Vault, auto-compounding strategy that continuously allocates your deposited
|
|
941
|
+
// asset to the best available yield source in the ecosystem. Depositors receive vault shares that
|
|
942
|
+
// represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are
|
|
943
|
+
// handled programmatically based on on-chain signals and risk filters, minimizing idle capital and
|
|
944
|
+
// maximizing net APY.
|
|
945
|
+
// </p>
|
|
946
|
+
|
|
947
|
+
// <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
|
|
948
|
+
// <p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
949
|
+
// <strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
|
|
950
|
+
// </p>
|
|
951
|
+
// </div>
|
|
952
|
+
|
|
953
|
+
// <h2 style={{ fontSize: "18px", marginBottom: "10px" }}>Supported Yield Sources</h2>
|
|
954
|
+
// {sources.map((s) => (
|
|
955
|
+
// <div key={s.key} style={cardStyle}>
|
|
956
|
+
// <div style={{ display: "flex", gap: "10px", alignItems: "flex-start" }}>
|
|
957
|
+
// <img src={logos[s.key]} alt={`${s.name} logo`} style={logoStyle} />
|
|
958
|
+
// <div style={{ flex: 1 }}>
|
|
959
|
+
// <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
|
960
|
+
// <h3 style={{ fontSize: "15px", margin: 0 }}>{s.name}</h3>
|
|
961
|
+
// <StatusBadge status={s.status} />
|
|
962
|
+
// </div>
|
|
963
|
+
// {/* <p style={{ fontSize: "13px", color: "#ccc", marginTop: "4px" }}>{s.description}</p> */}
|
|
964
|
+
// </div>
|
|
965
|
+
// </div>
|
|
966
|
+
// </div>
|
|
967
|
+
// ))}
|
|
968
|
+
// </div>
|
|
969
|
+
// );
|
|
970
|
+
// }
|
|
971
|
+
|
|
972
|
+
// function StatusBadge({ status }: { status: string }) {
|
|
973
|
+
// const isSoon = String(status).toLowerCase() !== "live";
|
|
974
|
+
// const badgeStyle = {
|
|
975
|
+
// fontSize: "12px",
|
|
976
|
+
// padding: "2px 6px",
|
|
977
|
+
// borderRadius: "12px",
|
|
978
|
+
// border: "1px solid",
|
|
979
|
+
// color: isSoon ? "rgb(196 196 195)" : "#6aff7d",
|
|
980
|
+
// borderColor: isSoon ? "#484848" : "#6aff7d",
|
|
981
|
+
// backgroundColor: isSoon ? "#424242" : "#002b1a",
|
|
982
|
+
// };
|
|
983
|
+
// return <span style={badgeStyle}>{status}</span>;
|
|
984
|
+
// }
|
|
985
|
+
|
|
986
|
+
// function getDescription(tokenSymbol: string, allowedSources: AllowedSources[]) {
|
|
987
|
+
// return MetaVaultDescription(allowedSources);
|
|
988
|
+
// }
|
|
989
|
+
|
|
990
|
+
// function getFAQs(): FAQ[] {
|
|
991
|
+
// return [
|
|
992
|
+
// {
|
|
993
|
+
// question: "What is the Meta Vault?",
|
|
994
|
+
// answer:
|
|
995
|
+
// "The Meta Vault is a tokenized strategy that automatically allocates your deposited assets to the best available yield source in the ecosystem. It optimizes returns while minimizing idle capital.",
|
|
996
|
+
// },
|
|
997
|
+
// {
|
|
998
|
+
// question: "How does yield allocation work?",
|
|
999
|
+
// answer:
|
|
1000
|
+
// "The vault continuously monitors supported protocols and routes liquidity to the source offering the highest net yield after accounting for fees, slippage, and gas costs. Reallocations are performed automatically.",
|
|
1001
|
+
// },
|
|
1002
|
+
// {
|
|
1003
|
+
// question: "Which yield sources are supported?",
|
|
1004
|
+
// answer: (
|
|
1005
|
+
// <span>
|
|
1006
|
+
// Currently, <strong>Vesu</strong> is live. Future integrations may include{" "}
|
|
1007
|
+
// <strong>Endur</strong>, <strong>Extended</strong>, and{" "}
|
|
1008
|
+
// <strong>Ekubo</strong> (all coming soon).
|
|
1009
|
+
// </span>
|
|
1010
|
+
// ),
|
|
1011
|
+
// },
|
|
1012
|
+
// {
|
|
1013
|
+
// question: "What do I receive when I deposit?",
|
|
1014
|
+
// answer:
|
|
1015
|
+
// "Depositors receive vault tokens representing their proportional share of the vault. These tokens entitle holders to both the principal and accrued yield.",
|
|
1016
|
+
// },
|
|
1017
|
+
// {
|
|
1018
|
+
// question: "How long do withdrawals take?",
|
|
1019
|
+
// answer:
|
|
1020
|
+
// "Withdrawals may take up to 1-2 hours to process, as the vault unwinds and settles liquidity routing across integrated protocols.",
|
|
1021
|
+
// },
|
|
1022
|
+
// {
|
|
1023
|
+
// question: "Is the Meta Vault non-custodial?",
|
|
1024
|
+
// answer:
|
|
1025
|
+
// "Yes. The Meta Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.",
|
|
1026
|
+
// },
|
|
1027
|
+
// {
|
|
1028
|
+
// question: "How is risk managed?",
|
|
1029
|
+
// answer:
|
|
1030
|
+
// "Integrations are supported with active risk monitoring like liquidation risk. Only vetted protocols are included to balance yield with safety. However, usual Defi risks like smart contract risk, extreme volatile market risk, etc. are still present.",
|
|
1031
|
+
// },
|
|
1032
|
+
// {
|
|
1033
|
+
// question: "Are there any fees?",
|
|
1034
|
+
// answer:
|
|
1035
|
+
// "Troves charges a performance of 10% on the yield generated. The APY shown is net of this fee. This fee is only applied to the profits earned, ensuring that users retain their initial capital.",
|
|
1036
|
+
// },
|
|
1037
|
+
// ];
|
|
1038
|
+
// }
|
|
1039
|
+
|
|
1040
|
+
export function getContractDetails(settings: UniversalStrategySettings & { aumOracle?: ContractAddr }): {address: ContractAddr, name: string}[] {
|
|
1041
|
+
const contracts = [
|
|
1127
1042
|
{ address: settings.vaultAddress, name: "Vault" },
|
|
1128
1043
|
{ address: settings.manager, name: "Vault Manager" },
|
|
1129
1044
|
{ address: settings.vaultAllocator, name: "Vault Allocator" },
|
|
1130
1045
|
{ address: settings.redeemRequestNFT, name: "Redeem Request NFT" },
|
|
1131
|
-
// { address: settings.aumOracle, name: "AUM Oracle" },
|
|
1132
1046
|
];
|
|
1047
|
+
if (settings.aumOracle) {
|
|
1048
|
+
contracts.push({ address: settings.aumOracle, name: "AUM Oracle" });
|
|
1049
|
+
}
|
|
1050
|
+
return contracts;
|
|
1133
1051
|
}
|
|
1134
1052
|
|
|
1135
|
-
const investmentSteps: string[] = [
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
]
|
|
1141
|
-
|
|
1142
|
-
const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
|
|
1143
|
-
export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1053
|
+
// const investmentSteps: string[] = [
|
|
1054
|
+
// "Deposit funds into the vault",
|
|
1055
|
+
// "Vault manager allocates funds to optimal yield sources",
|
|
1056
|
+
// "Vault manager reports asset under management (AUM) regularly to the vault",
|
|
1057
|
+
// "Request withdrawal and vault manager processes it in 1-2 hours"
|
|
1058
|
+
// ]
|
|
1059
|
+
|
|
1060
|
+
// const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
|
|
1061
|
+
// export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
|
|
1062
|
+
// [
|
|
1063
|
+
// {
|
|
1064
|
+
// name: "USDC Evergreen",
|
|
1065
|
+
// description: getDescription('USDC', ['vesu', 'extended']),
|
|
1066
|
+
// address: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
|
|
1067
|
+
// launchBlock: 0,
|
|
1068
|
+
// type: 'ERC4626',
|
|
1069
|
+
// depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDC')!],
|
|
1070
|
+
// additionalInfo: getLooperSettings('USDC', 'ETH', usdcVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1071
|
+
// risk: {
|
|
1072
|
+
// riskFactor: _riskFactor,
|
|
1073
|
+
// netRisk:
|
|
1074
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1075
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1076
|
+
// notARisks: getNoRiskTags(_riskFactor)
|
|
1077
|
+
// },
|
|
1078
|
+
// auditUrl: AUDIT_URL,
|
|
1079
|
+
// protocols: [Protocols.VESU],
|
|
1080
|
+
// maxTVL: Web3Number.fromWei(0, 6),
|
|
1081
|
+
// contractDetails: getContractDetails(usdcVaultSettings),
|
|
1082
|
+
// faqs: getFAQs(),
|
|
1083
|
+
// investmentSteps: investmentSteps,
|
|
1084
|
+
// },
|
|
1085
|
+
// {
|
|
1086
|
+
// name: "WBTC Evergreen",
|
|
1087
|
+
// description: getDescription('WBTC', ['vesu', 'endur', 'extended']),
|
|
1088
|
+
// address: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
|
|
1089
|
+
// launchBlock: 0,
|
|
1090
|
+
// type: 'ERC4626',
|
|
1091
|
+
// depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!],
|
|
1092
|
+
// additionalInfo: getLooperSettings('WBTC', 'ETH', wbtcVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1093
|
+
// risk: {
|
|
1094
|
+
// riskFactor: _riskFactor,
|
|
1095
|
+
// netRisk:
|
|
1096
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1097
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1098
|
+
// notARisks: getNoRiskTags(_riskFactor)
|
|
1099
|
+
// },
|
|
1100
|
+
// protocols: [Protocols.VESU],
|
|
1101
|
+
// maxTVL: Web3Number.fromWei(0, 8),
|
|
1102
|
+
// contractDetails: getContractDetails(wbtcVaultSettings),
|
|
1103
|
+
// faqs: getFAQs(),
|
|
1104
|
+
// investmentSteps: investmentSteps,
|
|
1105
|
+
// auditUrl: AUDIT_URL,
|
|
1106
|
+
// },
|
|
1107
|
+
// {
|
|
1108
|
+
// name: "ETH Evergreen",
|
|
1109
|
+
// description: getDescription('ETH', ['vesu', 'extended']),
|
|
1110
|
+
// address: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
|
|
1111
|
+
// launchBlock: 0,
|
|
1112
|
+
// type: 'ERC4626',
|
|
1113
|
+
// depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'ETH')!],
|
|
1114
|
+
// additionalInfo: getLooperSettings('ETH', 'WBTC', ethVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1115
|
+
// risk: {
|
|
1116
|
+
// riskFactor: _riskFactor,
|
|
1117
|
+
// netRisk:
|
|
1118
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1119
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1120
|
+
// notARisks: getNoRiskTags(_riskFactor)
|
|
1121
|
+
// },
|
|
1122
|
+
// protocols: [Protocols.VESU],
|
|
1123
|
+
// maxTVL: Web3Number.fromWei(0, 18),
|
|
1124
|
+
// contractDetails: getContractDetails(ethVaultSettings),
|
|
1125
|
+
// faqs: getFAQs(),
|
|
1126
|
+
// investmentSteps: investmentSteps,
|
|
1127
|
+
// auditUrl: AUDIT_URL,
|
|
1128
|
+
// },
|
|
1129
|
+
// {
|
|
1130
|
+
// name: "STRK Evergreen",
|
|
1131
|
+
// description: getDescription('STRK', ['vesu', 'endur', 'extended']),
|
|
1132
|
+
// address: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
|
|
1133
|
+
// launchBlock: 0,
|
|
1134
|
+
// type: 'ERC4626',
|
|
1135
|
+
// depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'STRK')!],
|
|
1136
|
+
// additionalInfo: getLooperSettings('STRK', 'ETH', strkVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1137
|
+
// risk: {
|
|
1138
|
+
// riskFactor: _riskFactor,
|
|
1139
|
+
// netRisk:
|
|
1140
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1141
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1142
|
+
// notARisks: getNoRiskTags(_riskFactor)
|
|
1143
|
+
// },
|
|
1144
|
+
// protocols: [Protocols.VESU],
|
|
1145
|
+
// maxTVL: Web3Number.fromWei(0, 18),
|
|
1146
|
+
// contractDetails: getContractDetails(strkVaultSettings),
|
|
1147
|
+
// faqs: getFAQs(),
|
|
1148
|
+
// investmentSteps: investmentSteps,
|
|
1149
|
+
// auditUrl: AUDIT_URL,
|
|
1150
|
+
// },
|
|
1151
|
+
// {
|
|
1152
|
+
// name: "USDT Evergreen",
|
|
1153
|
+
// description: getDescription('USDT', ['vesu']),
|
|
1154
|
+
// address: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
|
|
1155
|
+
// launchBlock: 0,
|
|
1156
|
+
// type: 'ERC4626',
|
|
1157
|
+
// depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDT')!],
|
|
1158
|
+
// additionalInfo: getLooperSettings('USDT', 'ETH', usdtVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1159
|
+
// risk: {
|
|
1160
|
+
// riskFactor: _riskFactor,
|
|
1161
|
+
// netRisk:
|
|
1162
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1163
|
+
// _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1164
|
+
// notARisks: getNoRiskTags(_riskFactor)
|
|
1165
|
+
// },
|
|
1166
|
+
// protocols: [Protocols.VESU],
|
|
1167
|
+
// maxTVL: Web3Number.fromWei(0, 6),
|
|
1168
|
+
// contractDetails: getContractDetails(usdtVaultSettings),
|
|
1169
|
+
// faqs: getFAQs(),
|
|
1170
|
+
// investmentSteps: investmentSteps,
|
|
1171
|
+
// auditUrl: AUDIT_URL,
|
|
1172
|
+
// }
|
|
1173
|
+
// ]
|