@strkfarm/sdk 1.0.18 → 1.0.20
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 +280 -90
- package/dist/cli.mjs +274 -84
- package/dist/index.browser.global.js +28406 -19296
- package/dist/index.browser.mjs +8068 -1366
- package/dist/index.d.ts +201 -24
- package/dist/index.js +7950 -1219
- package/dist/index.mjs +8100 -1377
- package/package.json +3 -1
- package/src/data/cl-vault.abi.json +1434 -0
- package/src/data/ekubo-math.abi.json +333 -0
- package/src/data/ekubo-positions.abi.json +1594 -0
- package/src/data/erc20.abi.json +1122 -0
- package/src/data/erc4626.abi.json +1530 -0
- package/src/dataTypes/_bignumber.ts +53 -0
- package/src/dataTypes/address.ts +4 -0
- package/src/dataTypes/bignumber.browser.ts +8 -0
- package/src/dataTypes/bignumber.node.ts +22 -0
- package/src/dataTypes/bignumber.ts +1 -55
- package/src/dataTypes/index.ts +1 -1
- package/src/global.ts +54 -4
- package/src/interfaces/common.ts +56 -9
- package/src/interfaces/lending.ts +1 -1
- package/src/modules/avnu.ts +93 -0
- package/src/modules/erc20.ts +23 -0
- package/src/modules/index.ts +2 -0
- package/src/modules/pricer.ts +1 -1
- package/src/modules/zkLend.ts +2 -2
- package/src/node/headless.browser.ts +9 -0
- package/src/node/headless.node.ts +36 -0
- package/src/node/headless.ts +1 -0
- package/src/node/index.ts +2 -1
- package/src/strategies/base-strategy.ts +47 -0
- package/src/strategies/ekubo-cl-vault.ts +535 -0
- package/src/strategies/index.ts +2 -1
- package/src/strategies/vesu-rebalance.ts +115 -25
|
@@ -7,6 +7,8 @@ import { Global } from "@/global";
|
|
|
7
7
|
import { assert } from "@/utils";
|
|
8
8
|
import axios from "axios";
|
|
9
9
|
import { PricerBase } from "@/modules/pricerBase";
|
|
10
|
+
import { BaseStrategy, SingleActionAmount, SingleTokenInfo } from "./base-strategy";
|
|
11
|
+
import { getAPIUsingHeadlessBrowser } from "@/node/headless";
|
|
10
12
|
|
|
11
13
|
interface PoolProps {
|
|
12
14
|
pool_id: ContractAddr;
|
|
@@ -21,6 +23,10 @@ interface Change {
|
|
|
21
23
|
isDeposit: boolean;
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
interface VesuRebalanceSettings {
|
|
27
|
+
feeBps: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
interface PoolInfoFull {
|
|
25
31
|
pool_id: ContractAddr;
|
|
26
32
|
pool_name: string | undefined;
|
|
@@ -42,15 +48,13 @@ interface PoolInfoFull {
|
|
|
42
48
|
* This class implements an automated rebalancing strategy for Vesu pools,
|
|
43
49
|
* managing deposits and withdrawals while optimizing yield through STRK rewards.
|
|
44
50
|
*/
|
|
45
|
-
export class VesuRebalance {
|
|
46
|
-
/** Configuration object for the strategy */
|
|
47
|
-
readonly config: IConfig;
|
|
51
|
+
export class VesuRebalance extends BaseStrategy<SingleTokenInfo, SingleActionAmount> {
|
|
48
52
|
/** Contract address of the strategy */
|
|
49
53
|
readonly address: ContractAddr;
|
|
50
54
|
/** Pricer instance for token price calculations */
|
|
51
55
|
readonly pricer: PricerBase;
|
|
52
56
|
/** Metadata containing strategy information */
|
|
53
|
-
readonly metadata: IStrategyMetadata
|
|
57
|
+
readonly metadata: IStrategyMetadata<VesuRebalanceSettings>;
|
|
54
58
|
/** Contract instance for interacting with the strategy */
|
|
55
59
|
readonly contract: Contract;
|
|
56
60
|
readonly BASE_WEIGHT = 10000; // 10000 bps = 100%
|
|
@@ -62,8 +66,8 @@ export class VesuRebalance {
|
|
|
62
66
|
* @param metadata - Strategy metadata including deposit tokens and address
|
|
63
67
|
* @throws {Error} If more than one deposit token is specified
|
|
64
68
|
*/
|
|
65
|
-
constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata) {
|
|
66
|
-
|
|
69
|
+
constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<VesuRebalanceSettings>) {
|
|
70
|
+
super(config);
|
|
67
71
|
this.pricer = pricer;
|
|
68
72
|
|
|
69
73
|
assert(metadata.depositTokens.length === 1, 'VesuRebalance only supports 1 deposit token');
|
|
@@ -79,12 +83,13 @@ export class VesuRebalance {
|
|
|
79
83
|
* @param receiver - Address that will receive the strategy tokens
|
|
80
84
|
* @returns Populated contract call for deposit
|
|
81
85
|
*/
|
|
82
|
-
depositCall(
|
|
86
|
+
depositCall(amountInfo: SingleActionAmount, receiver: ContractAddr) {
|
|
83
87
|
// Technically its not erc4626 abi, but we just need approve call
|
|
84
88
|
// so, its ok to use it
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const
|
|
89
|
+
assert(amountInfo.tokenInfo.address.eq(this.asset().address), 'Deposit token mismatch');
|
|
90
|
+
const assetContract = new Contract(VesuRebalanceAbi, this.asset().address.address, this.config.provider);
|
|
91
|
+
const call1 = assetContract.populate('approve', [this.address.address, uint256.bnToUint256(amountInfo.amount.toWei())]);
|
|
92
|
+
const call2 = this.contract.populate('deposit', [uint256.bnToUint256(amountInfo.amount.toWei()), receiver.address]);
|
|
88
93
|
return [call1, call2];
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -95,8 +100,8 @@ export class VesuRebalance {
|
|
|
95
100
|
* @param owner - Address that owns the strategy tokens
|
|
96
101
|
* @returns Populated contract call for withdrawal
|
|
97
102
|
*/
|
|
98
|
-
withdrawCall(
|
|
99
|
-
return [this.contract.populate('withdraw', [uint256.bnToUint256(
|
|
103
|
+
withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr) {
|
|
104
|
+
return [this.contract.populate('withdraw', [uint256.bnToUint256(amountInfo.amount.toWei()), receiver.address, owner.address])];
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
/**
|
|
@@ -127,6 +132,7 @@ export class VesuRebalance {
|
|
|
127
132
|
let price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
128
133
|
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
129
134
|
return {
|
|
135
|
+
tokenInfo: this.asset(),
|
|
130
136
|
amount,
|
|
131
137
|
usdValue
|
|
132
138
|
}
|
|
@@ -142,11 +148,30 @@ export class VesuRebalance {
|
|
|
142
148
|
let price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
143
149
|
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
144
150
|
return {
|
|
151
|
+
tokenInfo: this.asset(),
|
|
145
152
|
amount,
|
|
146
153
|
usdValue
|
|
147
154
|
}
|
|
148
155
|
}
|
|
149
156
|
|
|
157
|
+
static async getAllPossibleVerifiedPools(asset: ContractAddr) {
|
|
158
|
+
const data = await getAPIUsingHeadlessBrowser('https://api.vesu.xyz/pools');
|
|
159
|
+
const verifiedPools =data.data.filter((d: any) => d.isVerified);
|
|
160
|
+
const pools = verifiedPools.map((p: any) => {
|
|
161
|
+
const hasMyAsset = p.assets.find((a: any) => asset.eqString(a.address));
|
|
162
|
+
if (hasMyAsset) {
|
|
163
|
+
return {
|
|
164
|
+
pool_id: ContractAddr.from(p.id),
|
|
165
|
+
max_weight: 10000,
|
|
166
|
+
v_token: ContractAddr.from(hasMyAsset.vToken.address),
|
|
167
|
+
name: p.name,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
}).filter((p: PoolProps | null) => p !== null);
|
|
172
|
+
return pools;
|
|
173
|
+
}
|
|
174
|
+
|
|
150
175
|
/**
|
|
151
176
|
* Retrieves the list of allowed pools and their detailed information from multiple sources:
|
|
152
177
|
* 1. Contract's allowed pools
|
|
@@ -217,11 +242,10 @@ export class VesuRebalance {
|
|
|
217
242
|
let isErrorPositionsAPI = false;
|
|
218
243
|
let vesuPositions: any[] = [];
|
|
219
244
|
try {
|
|
220
|
-
const
|
|
221
|
-
const data = await res.data;
|
|
245
|
+
const data = await getAPIUsingHeadlessBrowser(`https://api.vesu.xyz/positions?walletAddress=${this.address.address}`)
|
|
222
246
|
vesuPositions = data.data;
|
|
223
247
|
} catch (e) {
|
|
224
|
-
console.error(`${VesuRebalance.name}: Error fetching
|
|
248
|
+
console.error(`${VesuRebalance.name}: Error fetching positions for ${this.address.address}`, e);
|
|
225
249
|
isErrorPositionsAPI = true;
|
|
226
250
|
}
|
|
227
251
|
|
|
@@ -229,8 +253,7 @@ export class VesuRebalance {
|
|
|
229
253
|
let isErrorPoolsAPI = false;
|
|
230
254
|
let pools: any[] = [];
|
|
231
255
|
try {
|
|
232
|
-
const
|
|
233
|
-
const data = await res.data;
|
|
256
|
+
const data = await getAPIUsingHeadlessBrowser('https://api.vesu.xyz/pools');
|
|
234
257
|
pools = data.data;
|
|
235
258
|
} catch (e) {
|
|
236
259
|
console.error(`${VesuRebalance.name}: Error fetching pools for ${this.address.address}`, e);
|
|
@@ -242,7 +265,7 @@ export class VesuRebalance {
|
|
|
242
265
|
const info = allowedPools.map(async (p) => {
|
|
243
266
|
const vesuPosition = vesuPositions.find((d: any) => d.pool.id.toString() === num.getDecimalString(p.pool_id.address.toString()));
|
|
244
267
|
const pool = pools.find((d: any) => d.id == num.getDecimalString(p.pool_id.address));
|
|
245
|
-
const assetInfo = pool?.assets.find((d: any) =>
|
|
268
|
+
const assetInfo = pool?.assets.find((d: any) => this.asset().address.eqString(d.address));
|
|
246
269
|
let vTokenContract = new Contract(VesuRebalanceAbi, p.v_token.address, this.config.provider);
|
|
247
270
|
const bal = await vTokenContract.balanceOf(this.address.address);
|
|
248
271
|
const assets = await vTokenContract.convert_to_assets(uint256.bnToUint256(bal.toString()));
|
|
@@ -297,7 +320,7 @@ export class VesuRebalance {
|
|
|
297
320
|
return acc + (curr.APY.netApy * weight);
|
|
298
321
|
}, 0);
|
|
299
322
|
|
|
300
|
-
return weightedApy;
|
|
323
|
+
return weightedApy * (1 - (this.metadata.additionalInfo.feeBps / 10000));
|
|
301
324
|
}
|
|
302
325
|
|
|
303
326
|
/**
|
|
@@ -447,22 +470,89 @@ const _protocol: IProtocol = {name: 'Vesu', logo: 'https://static-assets-8zct.on
|
|
|
447
470
|
// need to fine tune better
|
|
448
471
|
const _riskFactor: RiskFactor[] = [
|
|
449
472
|
{type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25},
|
|
450
|
-
{type: RiskType.TECHNICAL_RISK, value: 0.5, weight: 25},
|
|
451
473
|
{type: RiskType.COUNTERPARTY_RISK, value: 1, weight: 50},
|
|
474
|
+
{type: RiskType.ORACLE_RISK, value: 0.5, weight: 25},
|
|
452
475
|
]
|
|
476
|
+
const AUDIT_URL = 'https://assets.strkfarm.com/strkfarm/audit_report_vesu_and_ekubo_strats.pdf';
|
|
453
477
|
/**
|
|
454
478
|
* Represents the Vesu Rebalance Strategies.
|
|
455
479
|
*/
|
|
456
|
-
export const VesuRebalanceStrategies: IStrategyMetadata[] = [{
|
|
457
|
-
name: 'Vesu STRK',
|
|
480
|
+
export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[] = [{
|
|
481
|
+
name: 'Vesu Fusion STRK',
|
|
458
482
|
description: _description.replace('{{TOKEN}}', 'STRK'),
|
|
459
|
-
address: ContractAddr.from('
|
|
483
|
+
address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
460
484
|
type: 'ERC4626',
|
|
461
485
|
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'STRK')!],
|
|
462
486
|
protocols: [_protocol],
|
|
487
|
+
auditUrl: AUDIT_URL,
|
|
463
488
|
maxTVL: Web3Number.fromWei('0', 18),
|
|
464
489
|
risk: {
|
|
465
490
|
riskFactor: _riskFactor,
|
|
466
|
-
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
467
|
-
}
|
|
491
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
492
|
+
},
|
|
493
|
+
additionalInfo: {
|
|
494
|
+
feeBps: 1000,
|
|
495
|
+
},
|
|
496
|
+
}, {
|
|
497
|
+
name: 'Vesu Fusion ETH',
|
|
498
|
+
description: _description.replace('{{TOKEN}}', 'ETH'),
|
|
499
|
+
address: ContractAddr.from('0x26ea414fdf74ace1df5bc5ac72cbac670d438ef19b31edf9d59f98718fc0ab2'),
|
|
500
|
+
type: 'ERC4626',
|
|
501
|
+
auditUrl: AUDIT_URL,
|
|
502
|
+
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'ETH')!],
|
|
503
|
+
protocols: [_protocol],
|
|
504
|
+
maxTVL: Web3Number.fromWei('0', 18),
|
|
505
|
+
risk: {
|
|
506
|
+
riskFactor: _riskFactor,
|
|
507
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
508
|
+
},
|
|
509
|
+
additionalInfo: {
|
|
510
|
+
feeBps: 1000,
|
|
511
|
+
},
|
|
512
|
+
}, {
|
|
513
|
+
name: 'Vesu Fusion USDC',
|
|
514
|
+
description: _description.replace('{{TOKEN}}', 'USDC'),
|
|
515
|
+
address: ContractAddr.from('0x3a69adeb993cddb266962d9c995e3d0641dab627df22b825fa31bda460c3c14'),
|
|
516
|
+
type: 'ERC4626',
|
|
517
|
+
auditUrl: AUDIT_URL,
|
|
518
|
+
depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'USDC')!],
|
|
519
|
+
protocols: [_protocol],
|
|
520
|
+
maxTVL: Web3Number.fromWei('0', 6),
|
|
521
|
+
risk: {
|
|
522
|
+
riskFactor: _riskFactor,
|
|
523
|
+
netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
524
|
+
},
|
|
525
|
+
additionalInfo: {
|
|
526
|
+
feeBps: 1000,
|
|
527
|
+
},
|
|
528
|
+
// }, {
|
|
529
|
+
// name: 'Vesu Fusion USDT',
|
|
530
|
+
// description: _description.replace('{{TOKEN}}', 'USDT'),
|
|
531
|
+
// address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
532
|
+
// type: 'ERC4626',
|
|
533
|
+
// depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'USDT')!],
|
|
534
|
+
// protocols: [_protocol],
|
|
535
|
+
// maxTVL: Web3Number.fromWei('0', 6),
|
|
536
|
+
// risk: {
|
|
537
|
+
// riskFactor: _riskFactor,
|
|
538
|
+
// netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
539
|
+
// },
|
|
540
|
+
// additionalInfo: {
|
|
541
|
+
// feeBps: 1000,
|
|
542
|
+
// },
|
|
543
|
+
// }, {
|
|
544
|
+
// name: 'Vesu Fusion WBTC',
|
|
545
|
+
// description: _description.replace('{{TOKEN}}', 'WBTC'),
|
|
546
|
+
// address: ContractAddr.from('0x778007f8136a5b827325d21613803e796bda4d676fbe1e34aeab0b2a2ec027f'),
|
|
547
|
+
// type: 'ERC4626',
|
|
548
|
+
// depositTokens: [Global.getDefaultTokens().find(t => t.symbol === 'WBTC')!],
|
|
549
|
+
// protocols: [_protocol],
|
|
550
|
+
// maxTVL: Web3Number.fromWei('0', 8),
|
|
551
|
+
// risk: {
|
|
552
|
+
// riskFactor: _riskFactor,
|
|
553
|
+
// netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
554
|
+
// },
|
|
555
|
+
// additionalInfo: {
|
|
556
|
+
// feeBps: 1000,
|
|
557
|
+
// },
|
|
468
558
|
}]
|