@strkfarm/sdk 1.0.15 → 1.0.17

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.
@@ -0,0 +1,2582 @@
1
+ // src/modules/pricer.ts
2
+ import axios2 from "axios";
3
+
4
+ // src/global.ts
5
+ import axios from "axios";
6
+ var logger = {
7
+ ...console,
8
+ verbose(message) {
9
+ console.log(`[VERBOSE] ${message}`);
10
+ }
11
+ };
12
+ var FatalError = class extends Error {
13
+ constructor(message, err) {
14
+ super(message);
15
+ logger.error(message);
16
+ if (err)
17
+ logger.error(err.message);
18
+ this.name = "FatalError";
19
+ }
20
+ };
21
+ var tokens = [{
22
+ name: "Starknet",
23
+ symbol: "STRK",
24
+ logo: "https://assets.coingecko.com/coins/images/26433/small/starknet.png",
25
+ address: "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
26
+ decimals: 18,
27
+ coingeckId: "starknet"
28
+ }];
29
+ var Global = class {
30
+ static fatalError(message, err) {
31
+ logger.error(message);
32
+ console.error(message, err);
33
+ if (err)
34
+ console.error(err);
35
+ process.exit(1);
36
+ }
37
+ static httpError(url, err, message) {
38
+ logger.error(`${url}: ${message}`);
39
+ console.error(err);
40
+ }
41
+ static getDefaultTokens() {
42
+ return tokens;
43
+ }
44
+ static async getTokens() {
45
+ if (tokens.length) return tokens;
46
+ const data = await axios.get("https://starknet.api.avnu.fi/v1/starknet/tokens");
47
+ const tokensData = data.data.content;
48
+ tokensData.forEach((token) => {
49
+ if (!token.tags.includes("AVNU") || !token.tags.includes("Verified")) {
50
+ return;
51
+ }
52
+ tokens.push({
53
+ name: token.name,
54
+ symbol: token.symbol,
55
+ address: token.address,
56
+ decimals: token.decimals,
57
+ logo: token.logoUri,
58
+ coingeckId: token.extensions.coingeckoId
59
+ });
60
+ });
61
+ console.log(tokens);
62
+ return tokens;
63
+ }
64
+ static assert(condition, message) {
65
+ if (!condition) {
66
+ throw new FatalError(message);
67
+ }
68
+ }
69
+ };
70
+
71
+ // src/dataTypes/bignumber.ts
72
+ import BigNumber from "bignumber.js";
73
+ var Web3Number = class _Web3Number extends BigNumber {
74
+ constructor(value, decimals) {
75
+ super(value);
76
+ this.decimals = decimals;
77
+ }
78
+ static fromWei(weiNumber, decimals) {
79
+ const bn = new _Web3Number(weiNumber, decimals).dividedBy(10 ** decimals);
80
+ return new _Web3Number(bn.toString(), decimals);
81
+ }
82
+ toWei() {
83
+ return this.mul(10 ** this.decimals).toFixed(0);
84
+ }
85
+ multipliedBy(value) {
86
+ let _value = Number(value).toFixed(6);
87
+ return new _Web3Number(this.mul(_value).toString(), this.decimals);
88
+ }
89
+ dividedBy(value) {
90
+ let _value = Number(value).toFixed(6);
91
+ return new _Web3Number(this.div(_value).toString(), this.decimals);
92
+ }
93
+ plus(value) {
94
+ return new _Web3Number(this.add(value).toString(), this.decimals);
95
+ }
96
+ minus(n, base) {
97
+ return new _Web3Number(super.minus(n, base).toString(), this.decimals);
98
+ }
99
+ toString(base) {
100
+ return super.toString(base);
101
+ }
102
+ // [customInspectSymbol](depth: any, inspectOptions: any, inspect: any) {
103
+ // return this.toString();
104
+ // }
105
+ };
106
+ BigNumber.config({ DECIMAL_PLACES: 18 });
107
+ Web3Number.config({ DECIMAL_PLACES: 18 });
108
+
109
+ // src/dataTypes/address.ts
110
+ import { num } from "starknet";
111
+ var ContractAddr = class _ContractAddr {
112
+ constructor(address) {
113
+ this.address = _ContractAddr.standardise(address);
114
+ }
115
+ static from(address) {
116
+ return new _ContractAddr(address);
117
+ }
118
+ eq(other) {
119
+ return this.address === other.address;
120
+ }
121
+ eqString(other) {
122
+ return this.address === _ContractAddr.standardise(other);
123
+ }
124
+ static standardise(address) {
125
+ let _a = address;
126
+ if (!address) {
127
+ _a = "0";
128
+ }
129
+ const a = num.getHexString(num.getDecimalString(_a.toString()));
130
+ return a;
131
+ }
132
+ static eqString(a, b) {
133
+ return _ContractAddr.standardise(a) === _ContractAddr.standardise(b);
134
+ }
135
+ };
136
+
137
+ // src/modules/pricerBase.ts
138
+ var PricerBase = class {
139
+ constructor(config, tokens2) {
140
+ this.config = config;
141
+ this.tokens = tokens2;
142
+ }
143
+ async getPrice(tokenSymbol) {
144
+ throw new Error("Method not implemented");
145
+ }
146
+ };
147
+
148
+ // src/modules/pricer.ts
149
+ var Pricer = class extends PricerBase {
150
+ // e.g. ETH/USDC
151
+ constructor(config, tokens2) {
152
+ super(config, tokens2);
153
+ this.prices = {};
154
+ // code populates this map during runtime to determine which method to use for a given token
155
+ // The method set will be the first one to try after first attempt
156
+ this.methodToUse = {};
157
+ /**
158
+ * TOKENA and TOKENB are the two token names to get price of TokenA in terms of TokenB
159
+ */
160
+ this.PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
161
+ this.EKUBO_API = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8";
162
+ }
163
+ isReady() {
164
+ const allPricesExist = Object.keys(this.prices).length === this.tokens.length;
165
+ if (!allPricesExist) return false;
166
+ let atleastOneStale = false;
167
+ for (let token of this.tokens) {
168
+ const priceInfo = this.prices[token.symbol];
169
+ const isStale = this.isStale(priceInfo.timestamp, token.symbol);
170
+ if (isStale) {
171
+ atleastOneStale = true;
172
+ logger.warn(`Atleast one stale: ${token.symbol}: ${JSON.stringify(this.prices[token.symbol])}`);
173
+ break;
174
+ }
175
+ }
176
+ return allPricesExist && !atleastOneStale;
177
+ }
178
+ waitTillReady() {
179
+ return new Promise((resolve, reject) => {
180
+ const interval = setInterval(() => {
181
+ logger.verbose(`Waiting for pricer to initialise`);
182
+ if (this.isReady()) {
183
+ logger.verbose(`Pricer initialised`);
184
+ clearInterval(interval);
185
+ resolve();
186
+ }
187
+ }, 1e3);
188
+ });
189
+ }
190
+ start() {
191
+ this._loadPrices();
192
+ setInterval(() => {
193
+ this._loadPrices();
194
+ }, 3e4);
195
+ }
196
+ isStale(timestamp, tokenName) {
197
+ const STALE_TIME = 6e4;
198
+ return (/* @__PURE__ */ new Date()).getTime() - timestamp.getTime() > STALE_TIME;
199
+ }
200
+ assertNotStale(timestamp, tokenName) {
201
+ Global.assert(!this.isStale(timestamp, tokenName), `Price of ${tokenName} is stale`);
202
+ }
203
+ async getPrice(tokenSymbol) {
204
+ Global.assert(this.prices[tokenSymbol], `Price of ${tokenSymbol} not found`);
205
+ this.assertNotStale(this.prices[tokenSymbol].timestamp, tokenSymbol);
206
+ return this.prices[tokenSymbol];
207
+ }
208
+ _loadPrices(onUpdate = () => {
209
+ }) {
210
+ this.tokens.forEach(async (token) => {
211
+ const MAX_RETRIES = 10;
212
+ let retry = 0;
213
+ while (retry < MAX_RETRIES) {
214
+ try {
215
+ if (token.symbol === "USDT") {
216
+ this.prices[token.symbol] = {
217
+ price: 1,
218
+ timestamp: /* @__PURE__ */ new Date()
219
+ };
220
+ onUpdate(token.symbol);
221
+ return;
222
+ }
223
+ const price = await this._getPrice(token);
224
+ this.prices[token.symbol] = {
225
+ price,
226
+ timestamp: /* @__PURE__ */ new Date()
227
+ };
228
+ onUpdate(token.symbol);
229
+ logger.verbose(`Fetched price of ${token.name} as ${price}`);
230
+ break;
231
+ } catch (error) {
232
+ if (retry < MAX_RETRIES) {
233
+ logger.warn(`Error fetching data from ${token.name}, retry: ${retry}`);
234
+ logger.warn(error);
235
+ retry++;
236
+ await new Promise((resolve) => setTimeout(resolve, retry * 2e3));
237
+ } else {
238
+ throw new FatalError(`Error fetching data from ${token.name}`, error);
239
+ }
240
+ }
241
+ }
242
+ });
243
+ if (this.isReady() && this.config.heartbeatUrl) {
244
+ console.log(`sending beat`);
245
+ axios2.get(this.config.heartbeatUrl).catch((err) => {
246
+ console.error("Pricer: Heartbeat err", err);
247
+ });
248
+ }
249
+ }
250
+ async _getPrice(token, defaultMethod = "all") {
251
+ const methodToUse = this.methodToUse[token.symbol] || defaultMethod;
252
+ logger.info(`Fetching price of ${token.symbol} using ${methodToUse}`);
253
+ switch (methodToUse) {
254
+ case "Coinbase":
255
+ try {
256
+ const result = await this._getPriceCoinbase(token);
257
+ this.methodToUse[token.symbol] = "Coinbase";
258
+ return result;
259
+ } catch (error) {
260
+ console.warn(`Coinbase: price err: message [${token.symbol}]: `, error.message);
261
+ }
262
+ case "Coinmarketcap":
263
+ try {
264
+ const result = await this._getPriceCoinMarketCap(token);
265
+ this.methodToUse[token.symbol] = "Coinmarketcap";
266
+ return result;
267
+ } catch (error) {
268
+ console.warn(`CoinMarketCap: price err [${token.symbol}]: `, Object.keys(error));
269
+ console.warn(`CoinMarketCap: price err [${token.symbol}]: `, error.message);
270
+ }
271
+ case "Ekubo":
272
+ try {
273
+ const result = await this._getPriceEkubo(token);
274
+ this.methodToUse[token.symbol] = "Ekubo";
275
+ return result;
276
+ } catch (error) {
277
+ console.warn(`Ekubo: price err [${token.symbol}]: `, error.message);
278
+ console.warn(`Ekubo: price err [${token.symbol}]: `, Object.keys(error));
279
+ }
280
+ }
281
+ if (defaultMethod == "all") {
282
+ return await this._getPrice(token, "Coinbase");
283
+ }
284
+ throw new FatalError(`Price not found for ${token.symbol}`);
285
+ }
286
+ async _getPriceCoinbase(token) {
287
+ const url = this.PRICE_API.replace("{{PRICER_KEY}}", `${token.symbol}-USD`);
288
+ const result = await axios2.get(url);
289
+ const data = result.data;
290
+ return Number(data.data.amount);
291
+ }
292
+ async _getPriceCoinMarketCap(token) {
293
+ throw new Error("Not implemented");
294
+ }
295
+ async _getPriceEkubo(token, amountIn = new Web3Number(1, token.decimals), retry = 0) {
296
+ const url = this.EKUBO_API.replace("{{TOKEN_ADDRESS}}", token.address).replace("{{AMOUNT}}", amountIn.toWei());
297
+ const result = await axios2.get(url);
298
+ const data = result.data;
299
+ const outputUSDC = Number(Web3Number.fromWei(data.total_calculated, 6).toFixed(6));
300
+ logger.verbose(`Ekubo: ${token.symbol} -> USDC: ${outputUSDC}, retry: ${retry}`);
301
+ if (outputUSDC === 0 && retry < 3) {
302
+ const amountIn2 = new Web3Number(100, token.decimals);
303
+ return await this._getPriceEkubo(token, amountIn2, retry + 1);
304
+ }
305
+ const usdcPrice = 1;
306
+ logger.verbose(`USDC Price: ${usdcPrice}`);
307
+ return outputUSDC * usdcPrice;
308
+ }
309
+ };
310
+
311
+ // src/modules/pragma.ts
312
+ import { Contract } from "starknet";
313
+
314
+ // src/data/pragma.abi.json
315
+ var pragma_abi_default = [
316
+ {
317
+ data: [
318
+ {
319
+ name: "previousOwner",
320
+ type: "felt"
321
+ },
322
+ {
323
+ name: "newOwner",
324
+ type: "felt"
325
+ }
326
+ ],
327
+ keys: [],
328
+ name: "OwnershipTransferred",
329
+ type: "event"
330
+ },
331
+ {
332
+ data: [
333
+ {
334
+ name: "token",
335
+ type: "felt"
336
+ },
337
+ {
338
+ name: "source",
339
+ type: "felt"
340
+ }
341
+ ],
342
+ keys: [],
343
+ name: "TokenSourceChanged",
344
+ type: "event"
345
+ },
346
+ {
347
+ name: "constructor",
348
+ type: "constructor",
349
+ inputs: [
350
+ {
351
+ name: "owner",
352
+ type: "felt"
353
+ }
354
+ ],
355
+ outputs: []
356
+ },
357
+ {
358
+ name: "get_price",
359
+ type: "function",
360
+ inputs: [
361
+ {
362
+ name: "token",
363
+ type: "felt"
364
+ }
365
+ ],
366
+ outputs: [
367
+ {
368
+ name: "price",
369
+ type: "felt"
370
+ }
371
+ ],
372
+ stateMutability: "view"
373
+ },
374
+ {
375
+ name: "get_price_with_time",
376
+ type: "function",
377
+ inputs: [
378
+ {
379
+ name: "token",
380
+ type: "felt"
381
+ }
382
+ ],
383
+ outputs: [
384
+ {
385
+ name: "price",
386
+ type: "felt"
387
+ },
388
+ {
389
+ name: "update_time",
390
+ type: "felt"
391
+ }
392
+ ],
393
+ stateMutability: "view"
394
+ },
395
+ {
396
+ name: "set_token_source",
397
+ type: "function",
398
+ inputs: [
399
+ {
400
+ name: "token",
401
+ type: "felt"
402
+ },
403
+ {
404
+ name: "source",
405
+ type: "felt"
406
+ }
407
+ ],
408
+ outputs: []
409
+ }
410
+ ];
411
+
412
+ // src/modules/pragma.ts
413
+ var Pragma = class {
414
+ constructor(provider) {
415
+ this.contractAddr = "0x023fb3afbff2c0e3399f896dcf7400acf1a161941cfb386e34a123f228c62832";
416
+ this.contract = new Contract(pragma_abi_default, this.contractAddr, provider);
417
+ }
418
+ async getPrice(tokenAddr) {
419
+ if (!tokenAddr) {
420
+ throw new Error(`Pragma:getPrice - no token`);
421
+ }
422
+ const result = await this.contract.call("get_price", [tokenAddr]);
423
+ const price = Number(result.price) / 10 ** 8;
424
+ logger.verbose(`Pragma:${tokenAddr}: ${price}`);
425
+ return price;
426
+ }
427
+ };
428
+
429
+ // src/modules/zkLend.ts
430
+ import axios3 from "axios";
431
+
432
+ // src/interfaces/lending.ts
433
+ var MarginType = /* @__PURE__ */ ((MarginType2) => {
434
+ MarginType2["SHARED"] = "shared";
435
+ MarginType2["NONE"] = "none";
436
+ return MarginType2;
437
+ })(MarginType || {});
438
+ var ILending = class {
439
+ constructor(config, metadata) {
440
+ this.tokens = [];
441
+ this.initialised = false;
442
+ this.metadata = metadata;
443
+ this.config = config;
444
+ this.init();
445
+ }
446
+ /** Wait for initialisation */
447
+ waitForInitilisation() {
448
+ return new Promise((resolve, reject) => {
449
+ const interval = setInterval(() => {
450
+ logger.verbose(`Waiting for ${this.metadata.name} to initialise`);
451
+ if (this.initialised) {
452
+ logger.verbose(`${this.metadata.name} initialised`);
453
+ clearInterval(interval);
454
+ resolve();
455
+ }
456
+ }, 1e3);
457
+ });
458
+ }
459
+ };
460
+
461
+ // src/modules/zkLend.ts
462
+ var _ZkLend = class _ZkLend extends ILending {
463
+ constructor(config, pricer) {
464
+ super(config, {
465
+ name: "zkLend",
466
+ logo: "https://app.zklend.com/favicon.ico"
467
+ });
468
+ this.POSITION_URL = "https://app.zklend.com/api/users/{{USER_ADDR}}/all";
469
+ this.pricer = pricer;
470
+ }
471
+ async init() {
472
+ try {
473
+ logger.verbose(`Initialising ${this.metadata.name}`);
474
+ const result = await axios3.get(_ZkLend.POOLS_URL);
475
+ const data = result.data;
476
+ const savedTokens = await Global.getTokens();
477
+ data.forEach((pool) => {
478
+ let collareralFactor = new Web3Number(0, 0);
479
+ if (pool.collateral_factor) {
480
+ collareralFactor = Web3Number.fromWei(pool.collateral_factor.value, pool.collateral_factor.decimals);
481
+ }
482
+ const savedTokenInfo = savedTokens.find((t) => t.symbol == pool.token.symbol);
483
+ const token = {
484
+ name: pool.token.name,
485
+ symbol: pool.token.symbol,
486
+ address: savedTokenInfo?.address || "",
487
+ logo: "",
488
+ decimals: pool.token.decimals,
489
+ borrowFactor: Web3Number.fromWei(pool.borrow_factor.value, pool.borrow_factor.decimals),
490
+ collareralFactor
491
+ };
492
+ this.tokens.push(token);
493
+ });
494
+ logger.info(`Initialised ${this.metadata.name} with ${this.tokens.length} tokens`);
495
+ this.initialised = true;
496
+ } catch (error) {
497
+ return Global.httpError(_ZkLend.POOLS_URL, error);
498
+ }
499
+ }
500
+ /**
501
+ * @description Get the health factor of the user for given lending and debt tokens
502
+ * @param lending_tokens
503
+ * @param debt_tokens
504
+ * @param user
505
+ * @returns hf (e.g. returns 1.5 for 150% health factor)
506
+ */
507
+ async get_health_factor_tokenwise(lending_tokens, debt_tokens, user) {
508
+ const positions = await this.getPositions(user);
509
+ logger.verbose(`${this.metadata.name}:: Positions: ${JSON.stringify(positions)}`);
510
+ let effectiveDebt = new Web3Number(0, 6);
511
+ positions.filter((pos) => {
512
+ return debt_tokens.find((t) => t.symbol === pos.tokenSymbol);
513
+ }).forEach((pos) => {
514
+ const token = this.tokens.find((t) => t.symbol === pos.tokenSymbol);
515
+ if (!token) {
516
+ throw new FatalError(`Token ${pos.tokenName} not found in ${this.metadata.name}`);
517
+ }
518
+ effectiveDebt = effectiveDebt.plus(pos.debtUSD.dividedBy(token.borrowFactor.toFixed(6)).toString());
519
+ });
520
+ logger.verbose(`${this.metadata.name}:: Effective debt: ${effectiveDebt}`);
521
+ if (effectiveDebt.isZero()) {
522
+ return Infinity;
523
+ }
524
+ let effectiveCollateral = new Web3Number(0, 6);
525
+ positions.filter((pos) => {
526
+ const exp1 = lending_tokens.find((t) => t.symbol === pos.tokenSymbol);
527
+ const exp2 = pos.marginType === "shared" /* SHARED */;
528
+ return exp1 && exp2;
529
+ }).forEach((pos) => {
530
+ const token = this.tokens.find((t) => t.symbol === pos.tokenSymbol);
531
+ if (!token) {
532
+ throw new FatalError(`Token ${pos.tokenName} not found in ${this.metadata.name}`);
533
+ }
534
+ logger.verbose(`${this.metadata.name}:: Token: ${pos.tokenName}, Collateral factor: ${token.collareralFactor.toFixed(6)}`);
535
+ effectiveCollateral = effectiveCollateral.plus(pos.supplyUSD.multipliedBy(token.collareralFactor.toFixed(6)).toString());
536
+ });
537
+ logger.verbose(`${this.metadata.name}:: Effective collateral: ${effectiveCollateral}`);
538
+ const healthFactor = effectiveCollateral.dividedBy(effectiveDebt.toFixed(6)).toNumber();
539
+ logger.verbose(`${this.metadata.name}:: Health factor: ${healthFactor}`);
540
+ return healthFactor;
541
+ }
542
+ /**
543
+ * @description Get the health factor of the user
544
+ * - Considers all tokens for collateral and debt
545
+ */
546
+ async get_health_factor(user) {
547
+ return this.get_health_factor_tokenwise(this.tokens, this.tokens, user);
548
+ }
549
+ async getPositionsSummary(user) {
550
+ const pos = await this.getPositions(user);
551
+ const collateralUSD = pos.reduce((acc, p) => acc + p.supplyUSD.toNumber(), 0);
552
+ const debtUSD = pos.reduce((acc, p) => acc + p.debtUSD.toNumber(), 0);
553
+ return {
554
+ collateralUSD,
555
+ debtUSD
556
+ };
557
+ }
558
+ /**
559
+ * @description Get the token-wise collateral and debt positions of the user
560
+ * @param user Contract address of the user
561
+ * @returns Promise<ILendingPosition[]>
562
+ */
563
+ async getPositions(user) {
564
+ const url = this.POSITION_URL.replace("{{USER_ADDR}}", user.address);
565
+ const result = await axios3.get(url);
566
+ const data = result.data;
567
+ const lendingPosition = [];
568
+ logger.verbose(`${this.metadata.name}:: Positions: ${JSON.stringify(data)}`);
569
+ for (let i = 0; i < data.pools.length; i++) {
570
+ const pool = data.pools[i];
571
+ const token = this.tokens.find((t) => {
572
+ return t.symbol === pool.token_symbol;
573
+ });
574
+ if (!token) {
575
+ throw new FatalError(`Token ${pool.token_symbol} not found in ${this.metadata.name}`);
576
+ }
577
+ const debtAmount = Web3Number.fromWei(pool.data.debt_amount, token.decimals);
578
+ const supplyAmount = Web3Number.fromWei(pool.data.supply_amount, token.decimals);
579
+ const price = (await this.pricer.getPrice(token.symbol)).price;
580
+ lendingPosition.push({
581
+ tokenName: token.name,
582
+ tokenSymbol: token.symbol,
583
+ marginType: pool.data.is_collateral ? "shared" /* SHARED */ : "none" /* NONE */,
584
+ debtAmount,
585
+ debtUSD: debtAmount.multipliedBy(price.toFixed(6)),
586
+ supplyAmount,
587
+ supplyUSD: supplyAmount.multipliedBy(price.toFixed(6))
588
+ });
589
+ }
590
+ ;
591
+ return lendingPosition;
592
+ }
593
+ };
594
+ _ZkLend.POOLS_URL = "https://app.zklend.com/api/pools";
595
+ var ZkLend = _ZkLend;
596
+
597
+ // src/modules/pricer-from-api.ts
598
+ import axios4 from "axios";
599
+ var PricerFromApi = class extends PricerBase {
600
+ constructor(config, tokens2) {
601
+ super(config, tokens2);
602
+ }
603
+ async getPrice(tokenSymbol) {
604
+ try {
605
+ return await this.getPriceFromMyAPI(tokenSymbol);
606
+ } catch (e) {
607
+ logger.warn("getPriceFromMyAPI error", e);
608
+ }
609
+ logger.log("getPrice coinbase", tokenSymbol);
610
+ let retry = 0;
611
+ const MAX_RETRIES = 5;
612
+ for (retry = 1; retry < MAX_RETRIES + 1; retry++) {
613
+ try {
614
+ const priceInfo = await axios4.get(
615
+ `https://api.coinbase.com/v2/prices/${tokenSymbol}-USDT/spot`
616
+ );
617
+ if (!priceInfo) {
618
+ throw new Error("Failed to fetch price");
619
+ }
620
+ const data = await priceInfo.data;
621
+ const price = Number(data.data.amount);
622
+ return {
623
+ price,
624
+ timestamp: /* @__PURE__ */ new Date()
625
+ };
626
+ } catch (e) {
627
+ logger.warn("getPrice coinbase error", e, retry);
628
+ await new Promise((resolve) => setTimeout(resolve, retry * 1e3));
629
+ }
630
+ }
631
+ throw new Error(`Failed to fetch price for ${tokenSymbol}`);
632
+ }
633
+ async getPriceFromMyAPI(tokenSymbol) {
634
+ logger.verbose(`getPrice from redis: ${tokenSymbol}`);
635
+ const endpoint = "https://app.strkfarm.com";
636
+ const url = `${endpoint}/api/price/${tokenSymbol}`;
637
+ const priceInfoRes = await fetch(url);
638
+ const priceInfo = await priceInfoRes.json();
639
+ const now = /* @__PURE__ */ new Date();
640
+ const priceTime = new Date(priceInfo.timestamp);
641
+ if (now.getTime() - priceTime.getTime() > 9e5) {
642
+ throw new Error("Price is stale");
643
+ }
644
+ const price = Number(priceInfo.price);
645
+ return {
646
+ price,
647
+ timestamp: new Date(priceInfo.timestamp)
648
+ };
649
+ }
650
+ };
651
+
652
+ // src/interfaces/common.ts
653
+ import { RpcProvider as RpcProvider2 } from "starknet";
654
+ var RiskType = /* @__PURE__ */ ((RiskType2) => {
655
+ RiskType2["MARKET_RISK"] = "MARKET_RISK";
656
+ RiskType2["IMPERMANENT_LOSS"] = "IMPERMANENT_LOSS";
657
+ RiskType2["LIQUIDITY_RISK"] = "LIQUIDITY_RISK";
658
+ RiskType2["SMART_CONTRACT_RISK"] = "SMART_CONTRACT_RISK";
659
+ RiskType2["TECHNICAL_RISK"] = "TECHNICAL_RISK";
660
+ RiskType2["COUNTERPARTY_RISK"] = "COUNTERPARTY_RISK";
661
+ return RiskType2;
662
+ })(RiskType || {});
663
+ var Network = /* @__PURE__ */ ((Network2) => {
664
+ Network2["mainnet"] = "mainnet";
665
+ Network2["sepolia"] = "sepolia";
666
+ Network2["devnet"] = "devnet";
667
+ return Network2;
668
+ })(Network || {});
669
+ function getMainnetConfig(rpcUrl = "https://starknet-mainnet.public.blastapi.io", blockIdentifier = "pending") {
670
+ return {
671
+ provider: new RpcProvider2({
672
+ nodeUrl: rpcUrl,
673
+ blockIdentifier
674
+ }),
675
+ stage: "production",
676
+ network: "mainnet" /* mainnet */
677
+ };
678
+ }
679
+
680
+ // src/interfaces/initializable.ts
681
+ var Initializable = class {
682
+ constructor() {
683
+ this.initialized = false;
684
+ }
685
+ async waitForInitilisation() {
686
+ return new Promise((resolve, reject) => {
687
+ const interval = setInterval(() => {
688
+ if (this.initialized) {
689
+ console.log("Initialised");
690
+ clearInterval(interval);
691
+ resolve();
692
+ }
693
+ }, 1e3);
694
+ });
695
+ }
696
+ };
697
+
698
+ // src/strategies/autoCompounderStrk.ts
699
+ import { Contract as Contract2, uint256 } from "starknet";
700
+ var AutoCompounderSTRK = class {
701
+ constructor(config, pricer) {
702
+ this.addr = ContractAddr.from("0x541681b9ad63dff1b35f79c78d8477f64857de29a27902f7298f7b620838ea");
703
+ this.initialized = false;
704
+ this.contract = null;
705
+ this.metadata = {
706
+ decimals: 18,
707
+ underlying: {
708
+ // zSTRK
709
+ address: ContractAddr.from("0x06d8fa671ef84f791b7f601fa79fea8f6ceb70b5fa84189e3159d532162efc21"),
710
+ name: "STRK",
711
+ symbol: "STRK"
712
+ },
713
+ name: "AutoCompounderSTRK"
714
+ };
715
+ this.config = config;
716
+ this.pricer = pricer;
717
+ this.init();
718
+ }
719
+ async init() {
720
+ const provider = this.config.provider;
721
+ const cls = await provider.getClassAt(this.addr.address);
722
+ this.contract = new Contract2(cls.abi, this.addr.address, provider);
723
+ this.initialized = true;
724
+ }
725
+ async waitForInitilisation() {
726
+ return new Promise((resolve, reject) => {
727
+ const interval = setInterval(() => {
728
+ if (this.initialized) {
729
+ clearInterval(interval);
730
+ resolve();
731
+ }
732
+ }, 1e3);
733
+ });
734
+ }
735
+ /** Returns shares of user */
736
+ async balanceOf(user) {
737
+ const result = await this.contract.balanceOf(user.address);
738
+ return Web3Number.fromWei(result.toString(), this.metadata.decimals);
739
+ }
740
+ /** Returns underlying assets of user */
741
+ async balanceOfUnderlying(user) {
742
+ const balanceShares = await this.balanceOf(user);
743
+ const assets = await this.contract.convert_to_assets(uint256.bnToUint256(balanceShares.toWei()));
744
+ return Web3Number.fromWei(assets.toString(), this.metadata.decimals);
745
+ }
746
+ /** Returns usd value of assets */
747
+ async usdBalanceOfUnderlying(user) {
748
+ const assets = await this.balanceOfUnderlying(user);
749
+ const price = await this.pricer.getPrice(this.metadata.underlying.name);
750
+ const usd = assets.multipliedBy(price.price.toFixed(6));
751
+ return {
752
+ usd,
753
+ assets
754
+ };
755
+ }
756
+ };
757
+
758
+ // src/strategies/vesu-rebalance.ts
759
+ import { CairoCustomEnum, Contract as Contract3, num as num2, uint256 as uint2562 } from "starknet";
760
+
761
+ // src/data/vesu-rebalance.abi.json
762
+ var vesu_rebalance_abi_default = [
763
+ {
764
+ type: "impl",
765
+ name: "ExternalImpl",
766
+ interface_name: "strkfarm_contracts::strategies::vesu_rebalance::interface::IVesuRebal"
767
+ },
768
+ {
769
+ type: "enum",
770
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::Feature",
771
+ variants: [
772
+ {
773
+ name: "DEPOSIT",
774
+ type: "()"
775
+ },
776
+ {
777
+ name: "WITHDRAW",
778
+ type: "()"
779
+ }
780
+ ]
781
+ },
782
+ {
783
+ type: "struct",
784
+ name: "core::integer::u256",
785
+ members: [
786
+ {
787
+ name: "low",
788
+ type: "core::integer::u128"
789
+ },
790
+ {
791
+ name: "high",
792
+ type: "core::integer::u128"
793
+ }
794
+ ]
795
+ },
796
+ {
797
+ type: "struct",
798
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::Action",
799
+ members: [
800
+ {
801
+ name: "pool_id",
802
+ type: "core::felt252"
803
+ },
804
+ {
805
+ name: "feature",
806
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Feature"
807
+ },
808
+ {
809
+ name: "token",
810
+ type: "core::starknet::contract_address::ContractAddress"
811
+ },
812
+ {
813
+ name: "amount",
814
+ type: "core::integer::u256"
815
+ }
816
+ ]
817
+ },
818
+ {
819
+ type: "struct",
820
+ name: "strkfarm_contracts::interfaces::IEkuboDistributor::Claim",
821
+ members: [
822
+ {
823
+ name: "id",
824
+ type: "core::integer::u64"
825
+ },
826
+ {
827
+ name: "claimee",
828
+ type: "core::starknet::contract_address::ContractAddress"
829
+ },
830
+ {
831
+ name: "amount",
832
+ type: "core::integer::u128"
833
+ }
834
+ ]
835
+ },
836
+ {
837
+ type: "struct",
838
+ name: "core::array::Span::<core::felt252>",
839
+ members: [
840
+ {
841
+ name: "snapshot",
842
+ type: "@core::array::Array::<core::felt252>"
843
+ }
844
+ ]
845
+ },
846
+ {
847
+ type: "struct",
848
+ name: "strkfarm_contracts::components::swap::Route",
849
+ members: [
850
+ {
851
+ name: "token_from",
852
+ type: "core::starknet::contract_address::ContractAddress"
853
+ },
854
+ {
855
+ name: "token_to",
856
+ type: "core::starknet::contract_address::ContractAddress"
857
+ },
858
+ {
859
+ name: "exchange_address",
860
+ type: "core::starknet::contract_address::ContractAddress"
861
+ },
862
+ {
863
+ name: "percent",
864
+ type: "core::integer::u128"
865
+ },
866
+ {
867
+ name: "additional_swap_params",
868
+ type: "core::array::Array::<core::felt252>"
869
+ }
870
+ ]
871
+ },
872
+ {
873
+ type: "struct",
874
+ name: "strkfarm_contracts::components::swap::AvnuMultiRouteSwap",
875
+ members: [
876
+ {
877
+ name: "token_from_address",
878
+ type: "core::starknet::contract_address::ContractAddress"
879
+ },
880
+ {
881
+ name: "token_from_amount",
882
+ type: "core::integer::u256"
883
+ },
884
+ {
885
+ name: "token_to_address",
886
+ type: "core::starknet::contract_address::ContractAddress"
887
+ },
888
+ {
889
+ name: "token_to_amount",
890
+ type: "core::integer::u256"
891
+ },
892
+ {
893
+ name: "token_to_min_amount",
894
+ type: "core::integer::u256"
895
+ },
896
+ {
897
+ name: "beneficiary",
898
+ type: "core::starknet::contract_address::ContractAddress"
899
+ },
900
+ {
901
+ name: "integrator_fee_amount_bps",
902
+ type: "core::integer::u128"
903
+ },
904
+ {
905
+ name: "integrator_fee_recipient",
906
+ type: "core::starknet::contract_address::ContractAddress"
907
+ },
908
+ {
909
+ name: "routes",
910
+ type: "core::array::Array::<strkfarm_contracts::components::swap::Route>"
911
+ }
912
+ ]
913
+ },
914
+ {
915
+ type: "struct",
916
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings",
917
+ members: [
918
+ {
919
+ name: "default_pool_index",
920
+ type: "core::integer::u8"
921
+ },
922
+ {
923
+ name: "fee_bps",
924
+ type: "core::integer::u32"
925
+ },
926
+ {
927
+ name: "fee_receiver",
928
+ type: "core::starknet::contract_address::ContractAddress"
929
+ }
930
+ ]
931
+ },
932
+ {
933
+ type: "struct",
934
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps",
935
+ members: [
936
+ {
937
+ name: "pool_id",
938
+ type: "core::felt252"
939
+ },
940
+ {
941
+ name: "max_weight",
942
+ type: "core::integer::u32"
943
+ },
944
+ {
945
+ name: "v_token",
946
+ type: "core::starknet::contract_address::ContractAddress"
947
+ }
948
+ ]
949
+ },
950
+ {
951
+ type: "interface",
952
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::IVesuRebal",
953
+ items: [
954
+ {
955
+ type: "function",
956
+ name: "rebalance",
957
+ inputs: [
958
+ {
959
+ name: "actions",
960
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::Action>"
961
+ }
962
+ ],
963
+ outputs: [],
964
+ state_mutability: "external"
965
+ },
966
+ {
967
+ type: "function",
968
+ name: "rebalance_weights",
969
+ inputs: [
970
+ {
971
+ name: "actions",
972
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::Action>"
973
+ }
974
+ ],
975
+ outputs: [],
976
+ state_mutability: "external"
977
+ },
978
+ {
979
+ type: "function",
980
+ name: "emergency_withdraw",
981
+ inputs: [],
982
+ outputs: [],
983
+ state_mutability: "external"
984
+ },
985
+ {
986
+ type: "function",
987
+ name: "emergency_withdraw_pool",
988
+ inputs: [
989
+ {
990
+ name: "pool_index",
991
+ type: "core::integer::u32"
992
+ }
993
+ ],
994
+ outputs: [],
995
+ state_mutability: "external"
996
+ },
997
+ {
998
+ type: "function",
999
+ name: "compute_yield",
1000
+ inputs: [],
1001
+ outputs: [
1002
+ {
1003
+ type: "(core::integer::u256, core::integer::u256)"
1004
+ }
1005
+ ],
1006
+ state_mutability: "view"
1007
+ },
1008
+ {
1009
+ type: "function",
1010
+ name: "harvest",
1011
+ inputs: [
1012
+ {
1013
+ name: "rewardsContract",
1014
+ type: "core::starknet::contract_address::ContractAddress"
1015
+ },
1016
+ {
1017
+ name: "claim",
1018
+ type: "strkfarm_contracts::interfaces::IEkuboDistributor::Claim"
1019
+ },
1020
+ {
1021
+ name: "proof",
1022
+ type: "core::array::Span::<core::felt252>"
1023
+ },
1024
+ {
1025
+ name: "swapInfo",
1026
+ type: "strkfarm_contracts::components::swap::AvnuMultiRouteSwap"
1027
+ }
1028
+ ],
1029
+ outputs: [],
1030
+ state_mutability: "external"
1031
+ },
1032
+ {
1033
+ type: "function",
1034
+ name: "set_settings",
1035
+ inputs: [
1036
+ {
1037
+ name: "settings",
1038
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings"
1039
+ }
1040
+ ],
1041
+ outputs: [],
1042
+ state_mutability: "external"
1043
+ },
1044
+ {
1045
+ type: "function",
1046
+ name: "set_allowed_pools",
1047
+ inputs: [
1048
+ {
1049
+ name: "pools",
1050
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps>"
1051
+ }
1052
+ ],
1053
+ outputs: [],
1054
+ state_mutability: "external"
1055
+ },
1056
+ {
1057
+ type: "function",
1058
+ name: "set_incentives_off",
1059
+ inputs: [],
1060
+ outputs: [],
1061
+ state_mutability: "external"
1062
+ },
1063
+ {
1064
+ type: "function",
1065
+ name: "get_settings",
1066
+ inputs: [],
1067
+ outputs: [
1068
+ {
1069
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings"
1070
+ }
1071
+ ],
1072
+ state_mutability: "view"
1073
+ },
1074
+ {
1075
+ type: "function",
1076
+ name: "get_allowed_pools",
1077
+ inputs: [],
1078
+ outputs: [
1079
+ {
1080
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps>"
1081
+ }
1082
+ ],
1083
+ state_mutability: "view"
1084
+ },
1085
+ {
1086
+ type: "function",
1087
+ name: "get_previous_index",
1088
+ inputs: [],
1089
+ outputs: [
1090
+ {
1091
+ type: "core::integer::u128"
1092
+ }
1093
+ ],
1094
+ state_mutability: "view"
1095
+ }
1096
+ ]
1097
+ },
1098
+ {
1099
+ type: "impl",
1100
+ name: "VesuERC4626Impl",
1101
+ interface_name: "strkfarm_contracts::interfaces::IERC4626::IERC4626"
1102
+ },
1103
+ {
1104
+ type: "interface",
1105
+ name: "strkfarm_contracts::interfaces::IERC4626::IERC4626",
1106
+ items: [
1107
+ {
1108
+ type: "function",
1109
+ name: "asset",
1110
+ inputs: [],
1111
+ outputs: [
1112
+ {
1113
+ type: "core::starknet::contract_address::ContractAddress"
1114
+ }
1115
+ ],
1116
+ state_mutability: "view"
1117
+ },
1118
+ {
1119
+ type: "function",
1120
+ name: "total_assets",
1121
+ inputs: [],
1122
+ outputs: [
1123
+ {
1124
+ type: "core::integer::u256"
1125
+ }
1126
+ ],
1127
+ state_mutability: "view"
1128
+ },
1129
+ {
1130
+ type: "function",
1131
+ name: "convert_to_shares",
1132
+ inputs: [
1133
+ {
1134
+ name: "assets",
1135
+ type: "core::integer::u256"
1136
+ }
1137
+ ],
1138
+ outputs: [
1139
+ {
1140
+ type: "core::integer::u256"
1141
+ }
1142
+ ],
1143
+ state_mutability: "view"
1144
+ },
1145
+ {
1146
+ type: "function",
1147
+ name: "convert_to_assets",
1148
+ inputs: [
1149
+ {
1150
+ name: "shares",
1151
+ type: "core::integer::u256"
1152
+ }
1153
+ ],
1154
+ outputs: [
1155
+ {
1156
+ type: "core::integer::u256"
1157
+ }
1158
+ ],
1159
+ state_mutability: "view"
1160
+ },
1161
+ {
1162
+ type: "function",
1163
+ name: "max_deposit",
1164
+ inputs: [
1165
+ {
1166
+ name: "receiver",
1167
+ type: "core::starknet::contract_address::ContractAddress"
1168
+ }
1169
+ ],
1170
+ outputs: [
1171
+ {
1172
+ type: "core::integer::u256"
1173
+ }
1174
+ ],
1175
+ state_mutability: "view"
1176
+ },
1177
+ {
1178
+ type: "function",
1179
+ name: "preview_deposit",
1180
+ inputs: [
1181
+ {
1182
+ name: "assets",
1183
+ type: "core::integer::u256"
1184
+ }
1185
+ ],
1186
+ outputs: [
1187
+ {
1188
+ type: "core::integer::u256"
1189
+ }
1190
+ ],
1191
+ state_mutability: "view"
1192
+ },
1193
+ {
1194
+ type: "function",
1195
+ name: "deposit",
1196
+ inputs: [
1197
+ {
1198
+ name: "assets",
1199
+ type: "core::integer::u256"
1200
+ },
1201
+ {
1202
+ name: "receiver",
1203
+ type: "core::starknet::contract_address::ContractAddress"
1204
+ }
1205
+ ],
1206
+ outputs: [
1207
+ {
1208
+ type: "core::integer::u256"
1209
+ }
1210
+ ],
1211
+ state_mutability: "external"
1212
+ },
1213
+ {
1214
+ type: "function",
1215
+ name: "max_mint",
1216
+ inputs: [
1217
+ {
1218
+ name: "receiver",
1219
+ type: "core::starknet::contract_address::ContractAddress"
1220
+ }
1221
+ ],
1222
+ outputs: [
1223
+ {
1224
+ type: "core::integer::u256"
1225
+ }
1226
+ ],
1227
+ state_mutability: "view"
1228
+ },
1229
+ {
1230
+ type: "function",
1231
+ name: "preview_mint",
1232
+ inputs: [
1233
+ {
1234
+ name: "shares",
1235
+ type: "core::integer::u256"
1236
+ }
1237
+ ],
1238
+ outputs: [
1239
+ {
1240
+ type: "core::integer::u256"
1241
+ }
1242
+ ],
1243
+ state_mutability: "view"
1244
+ },
1245
+ {
1246
+ type: "function",
1247
+ name: "mint",
1248
+ inputs: [
1249
+ {
1250
+ name: "shares",
1251
+ type: "core::integer::u256"
1252
+ },
1253
+ {
1254
+ name: "receiver",
1255
+ type: "core::starknet::contract_address::ContractAddress"
1256
+ }
1257
+ ],
1258
+ outputs: [
1259
+ {
1260
+ type: "core::integer::u256"
1261
+ }
1262
+ ],
1263
+ state_mutability: "external"
1264
+ },
1265
+ {
1266
+ type: "function",
1267
+ name: "max_withdraw",
1268
+ inputs: [
1269
+ {
1270
+ name: "owner",
1271
+ type: "core::starknet::contract_address::ContractAddress"
1272
+ }
1273
+ ],
1274
+ outputs: [
1275
+ {
1276
+ type: "core::integer::u256"
1277
+ }
1278
+ ],
1279
+ state_mutability: "view"
1280
+ },
1281
+ {
1282
+ type: "function",
1283
+ name: "preview_withdraw",
1284
+ inputs: [
1285
+ {
1286
+ name: "assets",
1287
+ type: "core::integer::u256"
1288
+ }
1289
+ ],
1290
+ outputs: [
1291
+ {
1292
+ type: "core::integer::u256"
1293
+ }
1294
+ ],
1295
+ state_mutability: "view"
1296
+ },
1297
+ {
1298
+ type: "function",
1299
+ name: "withdraw",
1300
+ inputs: [
1301
+ {
1302
+ name: "assets",
1303
+ type: "core::integer::u256"
1304
+ },
1305
+ {
1306
+ name: "receiver",
1307
+ type: "core::starknet::contract_address::ContractAddress"
1308
+ },
1309
+ {
1310
+ name: "owner",
1311
+ type: "core::starknet::contract_address::ContractAddress"
1312
+ }
1313
+ ],
1314
+ outputs: [
1315
+ {
1316
+ type: "core::integer::u256"
1317
+ }
1318
+ ],
1319
+ state_mutability: "external"
1320
+ },
1321
+ {
1322
+ type: "function",
1323
+ name: "max_redeem",
1324
+ inputs: [
1325
+ {
1326
+ name: "owner",
1327
+ type: "core::starknet::contract_address::ContractAddress"
1328
+ }
1329
+ ],
1330
+ outputs: [
1331
+ {
1332
+ type: "core::integer::u256"
1333
+ }
1334
+ ],
1335
+ state_mutability: "view"
1336
+ },
1337
+ {
1338
+ type: "function",
1339
+ name: "preview_redeem",
1340
+ inputs: [
1341
+ {
1342
+ name: "shares",
1343
+ type: "core::integer::u256"
1344
+ }
1345
+ ],
1346
+ outputs: [
1347
+ {
1348
+ type: "core::integer::u256"
1349
+ }
1350
+ ],
1351
+ state_mutability: "view"
1352
+ },
1353
+ {
1354
+ type: "function",
1355
+ name: "redeem",
1356
+ inputs: [
1357
+ {
1358
+ name: "shares",
1359
+ type: "core::integer::u256"
1360
+ },
1361
+ {
1362
+ name: "receiver",
1363
+ type: "core::starknet::contract_address::ContractAddress"
1364
+ },
1365
+ {
1366
+ name: "owner",
1367
+ type: "core::starknet::contract_address::ContractAddress"
1368
+ }
1369
+ ],
1370
+ outputs: [
1371
+ {
1372
+ type: "core::integer::u256"
1373
+ }
1374
+ ],
1375
+ state_mutability: "external"
1376
+ }
1377
+ ]
1378
+ },
1379
+ {
1380
+ type: "impl",
1381
+ name: "VesuERC20Impl",
1382
+ interface_name: "openzeppelin_token::erc20::interface::IERC20Mixin"
1383
+ },
1384
+ {
1385
+ type: "enum",
1386
+ name: "core::bool",
1387
+ variants: [
1388
+ {
1389
+ name: "False",
1390
+ type: "()"
1391
+ },
1392
+ {
1393
+ name: "True",
1394
+ type: "()"
1395
+ }
1396
+ ]
1397
+ },
1398
+ {
1399
+ type: "struct",
1400
+ name: "core::byte_array::ByteArray",
1401
+ members: [
1402
+ {
1403
+ name: "data",
1404
+ type: "core::array::Array::<core::bytes_31::bytes31>"
1405
+ },
1406
+ {
1407
+ name: "pending_word",
1408
+ type: "core::felt252"
1409
+ },
1410
+ {
1411
+ name: "pending_word_len",
1412
+ type: "core::integer::u32"
1413
+ }
1414
+ ]
1415
+ },
1416
+ {
1417
+ type: "interface",
1418
+ name: "openzeppelin_token::erc20::interface::IERC20Mixin",
1419
+ items: [
1420
+ {
1421
+ type: "function",
1422
+ name: "total_supply",
1423
+ inputs: [],
1424
+ outputs: [
1425
+ {
1426
+ type: "core::integer::u256"
1427
+ }
1428
+ ],
1429
+ state_mutability: "view"
1430
+ },
1431
+ {
1432
+ type: "function",
1433
+ name: "balance_of",
1434
+ inputs: [
1435
+ {
1436
+ name: "account",
1437
+ type: "core::starknet::contract_address::ContractAddress"
1438
+ }
1439
+ ],
1440
+ outputs: [
1441
+ {
1442
+ type: "core::integer::u256"
1443
+ }
1444
+ ],
1445
+ state_mutability: "view"
1446
+ },
1447
+ {
1448
+ type: "function",
1449
+ name: "allowance",
1450
+ inputs: [
1451
+ {
1452
+ name: "owner",
1453
+ type: "core::starknet::contract_address::ContractAddress"
1454
+ },
1455
+ {
1456
+ name: "spender",
1457
+ type: "core::starknet::contract_address::ContractAddress"
1458
+ }
1459
+ ],
1460
+ outputs: [
1461
+ {
1462
+ type: "core::integer::u256"
1463
+ }
1464
+ ],
1465
+ state_mutability: "view"
1466
+ },
1467
+ {
1468
+ type: "function",
1469
+ name: "transfer",
1470
+ inputs: [
1471
+ {
1472
+ name: "recipient",
1473
+ type: "core::starknet::contract_address::ContractAddress"
1474
+ },
1475
+ {
1476
+ name: "amount",
1477
+ type: "core::integer::u256"
1478
+ }
1479
+ ],
1480
+ outputs: [
1481
+ {
1482
+ type: "core::bool"
1483
+ }
1484
+ ],
1485
+ state_mutability: "external"
1486
+ },
1487
+ {
1488
+ type: "function",
1489
+ name: "transfer_from",
1490
+ inputs: [
1491
+ {
1492
+ name: "sender",
1493
+ type: "core::starknet::contract_address::ContractAddress"
1494
+ },
1495
+ {
1496
+ name: "recipient",
1497
+ type: "core::starknet::contract_address::ContractAddress"
1498
+ },
1499
+ {
1500
+ name: "amount",
1501
+ type: "core::integer::u256"
1502
+ }
1503
+ ],
1504
+ outputs: [
1505
+ {
1506
+ type: "core::bool"
1507
+ }
1508
+ ],
1509
+ state_mutability: "external"
1510
+ },
1511
+ {
1512
+ type: "function",
1513
+ name: "approve",
1514
+ inputs: [
1515
+ {
1516
+ name: "spender",
1517
+ type: "core::starknet::contract_address::ContractAddress"
1518
+ },
1519
+ {
1520
+ name: "amount",
1521
+ type: "core::integer::u256"
1522
+ }
1523
+ ],
1524
+ outputs: [
1525
+ {
1526
+ type: "core::bool"
1527
+ }
1528
+ ],
1529
+ state_mutability: "external"
1530
+ },
1531
+ {
1532
+ type: "function",
1533
+ name: "name",
1534
+ inputs: [],
1535
+ outputs: [
1536
+ {
1537
+ type: "core::byte_array::ByteArray"
1538
+ }
1539
+ ],
1540
+ state_mutability: "view"
1541
+ },
1542
+ {
1543
+ type: "function",
1544
+ name: "symbol",
1545
+ inputs: [],
1546
+ outputs: [
1547
+ {
1548
+ type: "core::byte_array::ByteArray"
1549
+ }
1550
+ ],
1551
+ state_mutability: "view"
1552
+ },
1553
+ {
1554
+ type: "function",
1555
+ name: "decimals",
1556
+ inputs: [],
1557
+ outputs: [
1558
+ {
1559
+ type: "core::integer::u8"
1560
+ }
1561
+ ],
1562
+ state_mutability: "view"
1563
+ },
1564
+ {
1565
+ type: "function",
1566
+ name: "totalSupply",
1567
+ inputs: [],
1568
+ outputs: [
1569
+ {
1570
+ type: "core::integer::u256"
1571
+ }
1572
+ ],
1573
+ state_mutability: "view"
1574
+ },
1575
+ {
1576
+ type: "function",
1577
+ name: "balanceOf",
1578
+ inputs: [
1579
+ {
1580
+ name: "account",
1581
+ type: "core::starknet::contract_address::ContractAddress"
1582
+ }
1583
+ ],
1584
+ outputs: [
1585
+ {
1586
+ type: "core::integer::u256"
1587
+ }
1588
+ ],
1589
+ state_mutability: "view"
1590
+ },
1591
+ {
1592
+ type: "function",
1593
+ name: "transferFrom",
1594
+ inputs: [
1595
+ {
1596
+ name: "sender",
1597
+ type: "core::starknet::contract_address::ContractAddress"
1598
+ },
1599
+ {
1600
+ name: "recipient",
1601
+ type: "core::starknet::contract_address::ContractAddress"
1602
+ },
1603
+ {
1604
+ name: "amount",
1605
+ type: "core::integer::u256"
1606
+ }
1607
+ ],
1608
+ outputs: [
1609
+ {
1610
+ type: "core::bool"
1611
+ }
1612
+ ],
1613
+ state_mutability: "external"
1614
+ }
1615
+ ]
1616
+ },
1617
+ {
1618
+ type: "impl",
1619
+ name: "CommonCompImpl",
1620
+ interface_name: "strkfarm_contracts::interfaces::common::ICommon"
1621
+ },
1622
+ {
1623
+ type: "interface",
1624
+ name: "strkfarm_contracts::interfaces::common::ICommon",
1625
+ items: [
1626
+ {
1627
+ type: "function",
1628
+ name: "upgrade",
1629
+ inputs: [
1630
+ {
1631
+ name: "new_class",
1632
+ type: "core::starknet::class_hash::ClassHash"
1633
+ }
1634
+ ],
1635
+ outputs: [],
1636
+ state_mutability: "external"
1637
+ },
1638
+ {
1639
+ type: "function",
1640
+ name: "pause",
1641
+ inputs: [],
1642
+ outputs: [],
1643
+ state_mutability: "external"
1644
+ },
1645
+ {
1646
+ type: "function",
1647
+ name: "unpause",
1648
+ inputs: [],
1649
+ outputs: [],
1650
+ state_mutability: "external"
1651
+ },
1652
+ {
1653
+ type: "function",
1654
+ name: "is_paused",
1655
+ inputs: [],
1656
+ outputs: [
1657
+ {
1658
+ type: "core::bool"
1659
+ }
1660
+ ],
1661
+ state_mutability: "view"
1662
+ }
1663
+ ]
1664
+ },
1665
+ {
1666
+ type: "impl",
1667
+ name: "RewardShareImpl",
1668
+ interface_name: "strkfarm_contracts::components::harvester::reward_shares::IRewardShare"
1669
+ },
1670
+ {
1671
+ type: "struct",
1672
+ name: "strkfarm_contracts::components::harvester::reward_shares::UserRewardsInfo",
1673
+ members: [
1674
+ {
1675
+ name: "pending_round_points",
1676
+ type: "core::integer::u128"
1677
+ },
1678
+ {
1679
+ name: "shares_owned",
1680
+ type: "core::integer::u128"
1681
+ },
1682
+ {
1683
+ name: "block_number",
1684
+ type: "core::integer::u64"
1685
+ },
1686
+ {
1687
+ name: "index",
1688
+ type: "core::integer::u32"
1689
+ }
1690
+ ]
1691
+ },
1692
+ {
1693
+ type: "struct",
1694
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardsInfo",
1695
+ members: [
1696
+ {
1697
+ name: "amount",
1698
+ type: "core::integer::u128"
1699
+ },
1700
+ {
1701
+ name: "shares",
1702
+ type: "core::integer::u128"
1703
+ },
1704
+ {
1705
+ name: "total_round_points",
1706
+ type: "core::integer::u128"
1707
+ },
1708
+ {
1709
+ name: "block_number",
1710
+ type: "core::integer::u64"
1711
+ }
1712
+ ]
1713
+ },
1714
+ {
1715
+ type: "interface",
1716
+ name: "strkfarm_contracts::components::harvester::reward_shares::IRewardShare",
1717
+ items: [
1718
+ {
1719
+ type: "function",
1720
+ name: "get_user_reward_info",
1721
+ inputs: [
1722
+ {
1723
+ name: "user",
1724
+ type: "core::starknet::contract_address::ContractAddress"
1725
+ }
1726
+ ],
1727
+ outputs: [
1728
+ {
1729
+ type: "strkfarm_contracts::components::harvester::reward_shares::UserRewardsInfo"
1730
+ }
1731
+ ],
1732
+ state_mutability: "view"
1733
+ },
1734
+ {
1735
+ type: "function",
1736
+ name: "get_rewards_info",
1737
+ inputs: [
1738
+ {
1739
+ name: "index",
1740
+ type: "core::integer::u32"
1741
+ }
1742
+ ],
1743
+ outputs: [
1744
+ {
1745
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardsInfo"
1746
+ }
1747
+ ],
1748
+ state_mutability: "view"
1749
+ },
1750
+ {
1751
+ type: "function",
1752
+ name: "get_total_rewards",
1753
+ inputs: [],
1754
+ outputs: [
1755
+ {
1756
+ type: "core::integer::u32"
1757
+ }
1758
+ ],
1759
+ state_mutability: "view"
1760
+ },
1761
+ {
1762
+ type: "function",
1763
+ name: "get_total_unminted_shares",
1764
+ inputs: [],
1765
+ outputs: [
1766
+ {
1767
+ type: "core::integer::u128"
1768
+ }
1769
+ ],
1770
+ state_mutability: "view"
1771
+ },
1772
+ {
1773
+ type: "function",
1774
+ name: "get_additional_shares",
1775
+ inputs: [
1776
+ {
1777
+ name: "user",
1778
+ type: "core::starknet::contract_address::ContractAddress"
1779
+ }
1780
+ ],
1781
+ outputs: [
1782
+ {
1783
+ type: "(core::integer::u128, core::integer::u64, core::integer::u128)"
1784
+ }
1785
+ ],
1786
+ state_mutability: "view"
1787
+ }
1788
+ ]
1789
+ },
1790
+ {
1791
+ type: "struct",
1792
+ name: "strkfarm_contracts::interfaces::IVesu::IStonDispatcher",
1793
+ members: [
1794
+ {
1795
+ name: "contract_address",
1796
+ type: "core::starknet::contract_address::ContractAddress"
1797
+ }
1798
+ ]
1799
+ },
1800
+ {
1801
+ type: "struct",
1802
+ name: "strkfarm_contracts::components::vesu::vesuStruct",
1803
+ members: [
1804
+ {
1805
+ name: "singleton",
1806
+ type: "strkfarm_contracts::interfaces::IVesu::IStonDispatcher"
1807
+ },
1808
+ {
1809
+ name: "pool_id",
1810
+ type: "core::felt252"
1811
+ },
1812
+ {
1813
+ name: "debt",
1814
+ type: "core::starknet::contract_address::ContractAddress"
1815
+ },
1816
+ {
1817
+ name: "col",
1818
+ type: "core::starknet::contract_address::ContractAddress"
1819
+ },
1820
+ {
1821
+ name: "oracle",
1822
+ type: "core::starknet::contract_address::ContractAddress"
1823
+ }
1824
+ ]
1825
+ },
1826
+ {
1827
+ type: "constructor",
1828
+ name: "constructor",
1829
+ inputs: [
1830
+ {
1831
+ name: "asset",
1832
+ type: "core::starknet::contract_address::ContractAddress"
1833
+ },
1834
+ {
1835
+ name: "access_control",
1836
+ type: "core::starknet::contract_address::ContractAddress"
1837
+ },
1838
+ {
1839
+ name: "allowed_pools",
1840
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps>"
1841
+ },
1842
+ {
1843
+ name: "settings",
1844
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings"
1845
+ },
1846
+ {
1847
+ name: "vesu_settings",
1848
+ type: "strkfarm_contracts::components::vesu::vesuStruct"
1849
+ }
1850
+ ]
1851
+ },
1852
+ {
1853
+ type: "event",
1854
+ name: "openzeppelin_security::reentrancyguard::ReentrancyGuardComponent::Event",
1855
+ kind: "enum",
1856
+ variants: []
1857
+ },
1858
+ {
1859
+ type: "event",
1860
+ name: "strkfarm_contracts::components::erc4626::ERC4626Component::Deposit",
1861
+ kind: "struct",
1862
+ members: [
1863
+ {
1864
+ name: "sender",
1865
+ type: "core::starknet::contract_address::ContractAddress",
1866
+ kind: "key"
1867
+ },
1868
+ {
1869
+ name: "owner",
1870
+ type: "core::starknet::contract_address::ContractAddress",
1871
+ kind: "key"
1872
+ },
1873
+ {
1874
+ name: "assets",
1875
+ type: "core::integer::u256",
1876
+ kind: "data"
1877
+ },
1878
+ {
1879
+ name: "shares",
1880
+ type: "core::integer::u256",
1881
+ kind: "data"
1882
+ }
1883
+ ]
1884
+ },
1885
+ {
1886
+ type: "event",
1887
+ name: "strkfarm_contracts::components::erc4626::ERC4626Component::Withdraw",
1888
+ kind: "struct",
1889
+ members: [
1890
+ {
1891
+ name: "sender",
1892
+ type: "core::starknet::contract_address::ContractAddress",
1893
+ kind: "key"
1894
+ },
1895
+ {
1896
+ name: "receiver",
1897
+ type: "core::starknet::contract_address::ContractAddress",
1898
+ kind: "key"
1899
+ },
1900
+ {
1901
+ name: "owner",
1902
+ type: "core::starknet::contract_address::ContractAddress",
1903
+ kind: "key"
1904
+ },
1905
+ {
1906
+ name: "assets",
1907
+ type: "core::integer::u256",
1908
+ kind: "data"
1909
+ },
1910
+ {
1911
+ name: "shares",
1912
+ type: "core::integer::u256",
1913
+ kind: "data"
1914
+ }
1915
+ ]
1916
+ },
1917
+ {
1918
+ type: "event",
1919
+ name: "strkfarm_contracts::components::erc4626::ERC4626Component::Event",
1920
+ kind: "enum",
1921
+ variants: [
1922
+ {
1923
+ name: "Deposit",
1924
+ type: "strkfarm_contracts::components::erc4626::ERC4626Component::Deposit",
1925
+ kind: "nested"
1926
+ },
1927
+ {
1928
+ name: "Withdraw",
1929
+ type: "strkfarm_contracts::components::erc4626::ERC4626Component::Withdraw",
1930
+ kind: "nested"
1931
+ }
1932
+ ]
1933
+ },
1934
+ {
1935
+ type: "event",
1936
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Rewards",
1937
+ kind: "struct",
1938
+ members: [
1939
+ {
1940
+ name: "index",
1941
+ type: "core::integer::u32",
1942
+ kind: "data"
1943
+ },
1944
+ {
1945
+ name: "info",
1946
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardsInfo",
1947
+ kind: "data"
1948
+ },
1949
+ {
1950
+ name: "total_reward_shares",
1951
+ type: "core::integer::u128",
1952
+ kind: "data"
1953
+ },
1954
+ {
1955
+ name: "timestamp",
1956
+ type: "core::integer::u64",
1957
+ kind: "data"
1958
+ }
1959
+ ]
1960
+ },
1961
+ {
1962
+ type: "event",
1963
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::UserRewards",
1964
+ kind: "struct",
1965
+ members: [
1966
+ {
1967
+ name: "user",
1968
+ type: "core::starknet::contract_address::ContractAddress",
1969
+ kind: "key"
1970
+ },
1971
+ {
1972
+ name: "info",
1973
+ type: "strkfarm_contracts::components::harvester::reward_shares::UserRewardsInfo",
1974
+ kind: "data"
1975
+ },
1976
+ {
1977
+ name: "total_reward_shares",
1978
+ type: "core::integer::u128",
1979
+ kind: "data"
1980
+ },
1981
+ {
1982
+ name: "timestamp",
1983
+ type: "core::integer::u64",
1984
+ kind: "data"
1985
+ }
1986
+ ]
1987
+ },
1988
+ {
1989
+ type: "event",
1990
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Event",
1991
+ kind: "enum",
1992
+ variants: [
1993
+ {
1994
+ name: "Rewards",
1995
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Rewards",
1996
+ kind: "nested"
1997
+ },
1998
+ {
1999
+ name: "UserRewards",
2000
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::UserRewards",
2001
+ kind: "nested"
2002
+ }
2003
+ ]
2004
+ },
2005
+ {
2006
+ type: "event",
2007
+ name: "openzeppelin_token::erc20::erc20::ERC20Component::Transfer",
2008
+ kind: "struct",
2009
+ members: [
2010
+ {
2011
+ name: "from",
2012
+ type: "core::starknet::contract_address::ContractAddress",
2013
+ kind: "key"
2014
+ },
2015
+ {
2016
+ name: "to",
2017
+ type: "core::starknet::contract_address::ContractAddress",
2018
+ kind: "key"
2019
+ },
2020
+ {
2021
+ name: "value",
2022
+ type: "core::integer::u256",
2023
+ kind: "data"
2024
+ }
2025
+ ]
2026
+ },
2027
+ {
2028
+ type: "event",
2029
+ name: "openzeppelin_token::erc20::erc20::ERC20Component::Approval",
2030
+ kind: "struct",
2031
+ members: [
2032
+ {
2033
+ name: "owner",
2034
+ type: "core::starknet::contract_address::ContractAddress",
2035
+ kind: "key"
2036
+ },
2037
+ {
2038
+ name: "spender",
2039
+ type: "core::starknet::contract_address::ContractAddress",
2040
+ kind: "key"
2041
+ },
2042
+ {
2043
+ name: "value",
2044
+ type: "core::integer::u256",
2045
+ kind: "data"
2046
+ }
2047
+ ]
2048
+ },
2049
+ {
2050
+ type: "event",
2051
+ name: "openzeppelin_token::erc20::erc20::ERC20Component::Event",
2052
+ kind: "enum",
2053
+ variants: [
2054
+ {
2055
+ name: "Transfer",
2056
+ type: "openzeppelin_token::erc20::erc20::ERC20Component::Transfer",
2057
+ kind: "nested"
2058
+ },
2059
+ {
2060
+ name: "Approval",
2061
+ type: "openzeppelin_token::erc20::erc20::ERC20Component::Approval",
2062
+ kind: "nested"
2063
+ }
2064
+ ]
2065
+ },
2066
+ {
2067
+ type: "event",
2068
+ name: "openzeppelin_introspection::src5::SRC5Component::Event",
2069
+ kind: "enum",
2070
+ variants: []
2071
+ },
2072
+ {
2073
+ type: "event",
2074
+ name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
2075
+ kind: "struct",
2076
+ members: [
2077
+ {
2078
+ name: "class_hash",
2079
+ type: "core::starknet::class_hash::ClassHash",
2080
+ kind: "data"
2081
+ }
2082
+ ]
2083
+ },
2084
+ {
2085
+ type: "event",
2086
+ name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
2087
+ kind: "enum",
2088
+ variants: [
2089
+ {
2090
+ name: "Upgraded",
2091
+ type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
2092
+ kind: "nested"
2093
+ }
2094
+ ]
2095
+ },
2096
+ {
2097
+ type: "event",
2098
+ name: "openzeppelin_security::pausable::PausableComponent::Paused",
2099
+ kind: "struct",
2100
+ members: [
2101
+ {
2102
+ name: "account",
2103
+ type: "core::starknet::contract_address::ContractAddress",
2104
+ kind: "data"
2105
+ }
2106
+ ]
2107
+ },
2108
+ {
2109
+ type: "event",
2110
+ name: "openzeppelin_security::pausable::PausableComponent::Unpaused",
2111
+ kind: "struct",
2112
+ members: [
2113
+ {
2114
+ name: "account",
2115
+ type: "core::starknet::contract_address::ContractAddress",
2116
+ kind: "data"
2117
+ }
2118
+ ]
2119
+ },
2120
+ {
2121
+ type: "event",
2122
+ name: "openzeppelin_security::pausable::PausableComponent::Event",
2123
+ kind: "enum",
2124
+ variants: [
2125
+ {
2126
+ name: "Paused",
2127
+ type: "openzeppelin_security::pausable::PausableComponent::Paused",
2128
+ kind: "nested"
2129
+ },
2130
+ {
2131
+ name: "Unpaused",
2132
+ type: "openzeppelin_security::pausable::PausableComponent::Unpaused",
2133
+ kind: "nested"
2134
+ }
2135
+ ]
2136
+ },
2137
+ {
2138
+ type: "event",
2139
+ name: "strkfarm_contracts::components::common::CommonComp::Event",
2140
+ kind: "enum",
2141
+ variants: []
2142
+ },
2143
+ {
2144
+ type: "event",
2145
+ name: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::Rebalance",
2146
+ kind: "struct",
2147
+ members: [
2148
+ {
2149
+ name: "yield_before",
2150
+ type: "core::integer::u128",
2151
+ kind: "data"
2152
+ },
2153
+ {
2154
+ name: "yield_after",
2155
+ type: "core::integer::u128",
2156
+ kind: "data"
2157
+ }
2158
+ ]
2159
+ },
2160
+ {
2161
+ type: "event",
2162
+ name: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::CollectFees",
2163
+ kind: "struct",
2164
+ members: [
2165
+ {
2166
+ name: "fee_collected",
2167
+ type: "core::integer::u128",
2168
+ kind: "data"
2169
+ },
2170
+ {
2171
+ name: "fee_collector",
2172
+ type: "core::starknet::contract_address::ContractAddress",
2173
+ kind: "data"
2174
+ }
2175
+ ]
2176
+ },
2177
+ {
2178
+ type: "event",
2179
+ name: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::Event",
2180
+ kind: "enum",
2181
+ variants: [
2182
+ {
2183
+ name: "ReentrancyGuardEvent",
2184
+ type: "openzeppelin_security::reentrancyguard::ReentrancyGuardComponent::Event",
2185
+ kind: "flat"
2186
+ },
2187
+ {
2188
+ name: "ERC4626Event",
2189
+ type: "strkfarm_contracts::components::erc4626::ERC4626Component::Event",
2190
+ kind: "flat"
2191
+ },
2192
+ {
2193
+ name: "RewardShareEvent",
2194
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Event",
2195
+ kind: "flat"
2196
+ },
2197
+ {
2198
+ name: "ERC20Event",
2199
+ type: "openzeppelin_token::erc20::erc20::ERC20Component::Event",
2200
+ kind: "flat"
2201
+ },
2202
+ {
2203
+ name: "SRC5Event",
2204
+ type: "openzeppelin_introspection::src5::SRC5Component::Event",
2205
+ kind: "flat"
2206
+ },
2207
+ {
2208
+ name: "UpgradeableEvent",
2209
+ type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
2210
+ kind: "flat"
2211
+ },
2212
+ {
2213
+ name: "PausableEvent",
2214
+ type: "openzeppelin_security::pausable::PausableComponent::Event",
2215
+ kind: "flat"
2216
+ },
2217
+ {
2218
+ name: "CommonCompEvent",
2219
+ type: "strkfarm_contracts::components::common::CommonComp::Event",
2220
+ kind: "flat"
2221
+ },
2222
+ {
2223
+ name: "Rebalance",
2224
+ type: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::Rebalance",
2225
+ kind: "nested"
2226
+ },
2227
+ {
2228
+ name: "CollectFees",
2229
+ type: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::CollectFees",
2230
+ kind: "nested"
2231
+ }
2232
+ ]
2233
+ }
2234
+ ];
2235
+
2236
+ // src/utils/index.ts
2237
+ function assert(condition, message) {
2238
+ if (!condition) {
2239
+ throw new Error(message);
2240
+ }
2241
+ }
2242
+
2243
+ // src/strategies/vesu-rebalance.ts
2244
+ import axios5 from "axios";
2245
+ var VesuRebalance = class _VesuRebalance {
2246
+ // 10000 bps = 100%
2247
+ /**
2248
+ * Creates a new VesuRebalance strategy instance.
2249
+ * @param config - Configuration object containing provider and other settings
2250
+ * @param pricer - Pricer instance for token price calculations
2251
+ * @param metadata - Strategy metadata including deposit tokens and address
2252
+ * @throws {Error} If more than one deposit token is specified
2253
+ */
2254
+ constructor(config, pricer, metadata) {
2255
+ this.BASE_WEIGHT = 1e4;
2256
+ this.config = config;
2257
+ this.pricer = pricer;
2258
+ assert(metadata.depositTokens.length === 1, "VesuRebalance only supports 1 deposit token");
2259
+ this.metadata = metadata;
2260
+ this.address = metadata.address;
2261
+ this.contract = new Contract3(vesu_rebalance_abi_default, this.address.address, this.config.provider);
2262
+ }
2263
+ /**
2264
+ * Creates a deposit call to the strategy contract.
2265
+ * @param assets - Amount of assets to deposit
2266
+ * @param receiver - Address that will receive the strategy tokens
2267
+ * @returns Populated contract call for deposit
2268
+ */
2269
+ depositCall(assets, receiver) {
2270
+ const assetContract = new Contract3(vesu_rebalance_abi_default, this.metadata.depositTokens[0].address, this.config.provider);
2271
+ const call1 = assetContract.populate("approve", [this.address.address, uint2562.bnToUint256(assets.toWei())]);
2272
+ const call2 = this.contract.populate("deposit", [uint2562.bnToUint256(assets.toWei()), receiver.address]);
2273
+ return [call1, call2];
2274
+ }
2275
+ /**
2276
+ * Creates a withdrawal call to the strategy contract.
2277
+ * @param assets - Amount of assets to withdraw
2278
+ * @param receiver - Address that will receive the withdrawn assets
2279
+ * @param owner - Address that owns the strategy tokens
2280
+ * @returns Populated contract call for withdrawal
2281
+ */
2282
+ withdrawCall(assets, receiver, owner) {
2283
+ return [this.contract.populate("withdraw", [uint2562.bnToUint256(assets.toWei()), receiver.address, owner.address])];
2284
+ }
2285
+ /**
2286
+ * Returns the underlying asset token of the strategy.
2287
+ * @returns The deposit token supported by this strategy
2288
+ */
2289
+ asset() {
2290
+ return this.metadata.depositTokens[0];
2291
+ }
2292
+ /**
2293
+ * Returns the number of decimals used by the strategy token.
2294
+ * @returns Number of decimals (same as the underlying token)
2295
+ */
2296
+ decimals() {
2297
+ return this.metadata.depositTokens[0].decimals;
2298
+ }
2299
+ /**
2300
+ * Calculates the Total Value Locked (TVL) for a specific user.
2301
+ * @param user - Address of the user
2302
+ * @returns Object containing the amount in token units and USD value
2303
+ */
2304
+ async getUserTVL(user) {
2305
+ const shares = await this.contract.balanceOf(user.address);
2306
+ const assets = await this.contract.convert_to_assets(uint2562.bnToUint256(shares));
2307
+ const amount = Web3Number.fromWei(assets.toString(), this.metadata.depositTokens[0].decimals);
2308
+ let price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
2309
+ const usdValue = Number(amount.toFixed(6)) * price.price;
2310
+ return {
2311
+ amount,
2312
+ usdValue
2313
+ };
2314
+ }
2315
+ /**
2316
+ * Calculates the total TVL of the strategy.
2317
+ * @returns Object containing the total amount in token units and USD value
2318
+ */
2319
+ async getTVL() {
2320
+ const assets = await this.contract.total_assets();
2321
+ const amount = Web3Number.fromWei(assets.toString(), this.metadata.depositTokens[0].decimals);
2322
+ let price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
2323
+ const usdValue = Number(amount.toFixed(6)) * price.price;
2324
+ return {
2325
+ amount,
2326
+ usdValue
2327
+ };
2328
+ }
2329
+ /**
2330
+ * Retrieves the list of allowed pools and their detailed information from multiple sources:
2331
+ * 1. Contract's allowed pools
2332
+ * 2. Vesu positions API for current positions
2333
+ * 3. Vesu pools API for APY and utilization data
2334
+ *
2335
+ * @returns {Promise<{
2336
+ * data: Array<PoolInfoFull>,
2337
+ * isErrorPositionsAPI: boolean
2338
+ * }>} Object containing:
2339
+ * - data: Array of pool information including IDs, weights, amounts, APYs and utilization
2340
+ * - isErrorPositionsAPI: Boolean indicating if there was an error fetching position data
2341
+ */
2342
+ async getPools() {
2343
+ const allowedPools = (await this.contract.get_allowed_pools()).map((p) => ({
2344
+ pool_id: ContractAddr.from(p.pool_id),
2345
+ max_weight: Number(p.max_weight) / this.BASE_WEIGHT,
2346
+ v_token: ContractAddr.from(p.v_token)
2347
+ }));
2348
+ let isErrorPositionsAPI = false;
2349
+ let vesuPositions = [];
2350
+ try {
2351
+ const res = await axios5.get(`https://api.vesu.xyz/positions?walletAddress=${this.address.address}`);
2352
+ const data2 = await res.data;
2353
+ vesuPositions = data2.data;
2354
+ } catch (e) {
2355
+ console.error(`${_VesuRebalance.name}: Error fetching pools for ${this.address.address}`, e);
2356
+ isErrorPositionsAPI = true;
2357
+ }
2358
+ let isErrorPoolsAPI = false;
2359
+ let pools = [];
2360
+ try {
2361
+ const res = await axios5.get(`https://api.vesu.xyz/pools`);
2362
+ const data2 = await res.data;
2363
+ pools = data2.data;
2364
+ } catch (e) {
2365
+ console.error(`${_VesuRebalance.name}: Error fetching pools for ${this.address.address}`, e);
2366
+ isErrorPoolsAPI = true;
2367
+ }
2368
+ const totalAssets = (await this.getTVL()).amount;
2369
+ const info = allowedPools.map(async (p) => {
2370
+ const vesuPosition = vesuPositions.find((d) => d.pool.id.toString() === num2.getDecimalString(p.pool_id.address.toString()));
2371
+ const pool = pools.find((d) => d.id == num2.getDecimalString(p.pool_id.address));
2372
+ const assetInfo = pool?.assets.find((d) => ContractAddr.from(this.asset().address).eqString(d.address));
2373
+ let vTokenContract = new Contract3(vesu_rebalance_abi_default, p.v_token.address, this.config.provider);
2374
+ const bal = await vTokenContract.balanceOf(this.address.address);
2375
+ const assets = await vTokenContract.convert_to_assets(uint2562.bnToUint256(bal.toString()));
2376
+ const item = {
2377
+ pool_id: p.pool_id,
2378
+ pool_name: vesuPosition?.pool.name,
2379
+ max_weight: p.max_weight,
2380
+ current_weight: isErrorPositionsAPI || !vesuPosition ? 0 : Number(Web3Number.fromWei(vesuPosition.collateral.value, this.decimals()).dividedBy(totalAssets.toString()).toFixed(6)),
2381
+ v_token: p.v_token,
2382
+ amount: Web3Number.fromWei(assets.toString(), this.decimals()),
2383
+ usdValue: isErrorPositionsAPI || !vesuPosition ? Web3Number.fromWei("0", this.decimals()) : Web3Number.fromWei(vesuPosition.collateral.usdPrice.value, vesuPosition.collateral.usdPrice.decimals),
2384
+ APY: isErrorPoolsAPI || !assetInfo ? {
2385
+ baseApy: 0,
2386
+ defiSpringApy: 0,
2387
+ netApy: 0
2388
+ } : {
2389
+ baseApy: Number(Web3Number.fromWei(assetInfo.stats.supplyApy.value, assetInfo.stats.supplyApy.decimals).toFixed(6)),
2390
+ defiSpringApy: Number(Web3Number.fromWei(assetInfo.stats.defiSpringSupplyApr.value, assetInfo.stats.defiSpringSupplyApr.decimals).toFixed(6)),
2391
+ netApy: 0
2392
+ },
2393
+ currentUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(Web3Number.fromWei(assetInfo.stats.currentUtilization.value, assetInfo.stats.currentUtilization.decimals).toFixed(6)),
2394
+ maxUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(Web3Number.fromWei(assetInfo.config.maxUtilization.value, assetInfo.config.maxUtilization.decimals).toFixed(6))
2395
+ };
2396
+ item.APY.netApy = item.APY.baseApy + item.APY.defiSpringApy;
2397
+ return item;
2398
+ });
2399
+ const data = await Promise.all(info);
2400
+ return {
2401
+ data,
2402
+ isErrorPositionsAPI,
2403
+ isErrorPoolsAPI,
2404
+ isError: isErrorPositionsAPI || isErrorPoolsAPI
2405
+ };
2406
+ }
2407
+ /**
2408
+ * Calculates the weighted average APY across all pools based on USD value.
2409
+ * @returns {Promise<number>} The weighted average APY across all pools
2410
+ */
2411
+ async netAPY() {
2412
+ const { data: pools } = await this.getPools();
2413
+ return this.netAPYGivenPools(pools);
2414
+ }
2415
+ /**
2416
+ * Calculates the weighted average APY across all pools based on USD value.
2417
+ * @returns {Promise<number>} The weighted average APY across all pools
2418
+ */
2419
+ netAPYGivenPools(pools) {
2420
+ const weightedApy = pools.reduce((acc, curr) => {
2421
+ const weight = curr.current_weight;
2422
+ return acc + curr.APY.netApy * weight;
2423
+ }, 0);
2424
+ return weightedApy;
2425
+ }
2426
+ /**
2427
+ * Calculates optimal position changes to maximize APY while respecting max weights.
2428
+ * The algorithm:
2429
+ * 1. Sorts pools by APY (highest first)
2430
+ * 2. Calculates target amounts based on max weights
2431
+ * 3. For each pool that needs more funds:
2432
+ * - Takes funds from lowest APY pools that are over their target
2433
+ * 4. Validates that total assets remain constant
2434
+ *
2435
+ * @returns {Promise<{
2436
+ * changes: Change[],
2437
+ * finalPools: PoolInfoFull[],
2438
+ * isAnyPoolOverMaxWeight: boolean
2439
+ * }>} Object containing:
2440
+ * - changes: Array of position changes
2441
+ * - finalPools: Array of pool information after rebalance
2442
+ * @throws Error if rebalance is not possible while maintaining constraints
2443
+ */
2444
+ async getRebalancedPositions() {
2445
+ const { data: pools } = await this.getPools();
2446
+ const totalAssets = (await this.getTVL()).amount;
2447
+ if (totalAssets.eq(0)) return {
2448
+ changes: [],
2449
+ finalPools: []
2450
+ };
2451
+ const sumPools = pools.reduce((acc, curr) => acc.plus(curr.amount.toString()), Web3Number.fromWei("0", this.decimals()));
2452
+ assert(sumPools.lte(totalAssets), "Sum of pools.amount must be less than or equal to totalAssets");
2453
+ const sortedPools = [...pools].sort((a, b) => b.APY.netApy - a.APY.netApy);
2454
+ const targetAmounts = {};
2455
+ let remainingAssets = totalAssets;
2456
+ let isAnyPoolOverMaxWeight = false;
2457
+ for (const pool of sortedPools) {
2458
+ const maxAmount = totalAssets.multipliedBy(pool.max_weight * 0.9);
2459
+ const targetAmount = remainingAssets.gte(maxAmount) ? maxAmount : remainingAssets;
2460
+ targetAmounts[pool.pool_id.address.toString()] = targetAmount;
2461
+ remainingAssets = remainingAssets.minus(targetAmount.toString());
2462
+ if (pool.current_weight > pool.max_weight) {
2463
+ isAnyPoolOverMaxWeight = true;
2464
+ }
2465
+ }
2466
+ assert(remainingAssets.lt(1e-5), "Remaining assets must be 0");
2467
+ const changes = sortedPools.map((pool) => {
2468
+ const target = targetAmounts[pool.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
2469
+ const change = Web3Number.fromWei(target.minus(pool.amount.toString()).toWei(), this.decimals());
2470
+ return {
2471
+ pool_id: pool.pool_id,
2472
+ changeAmt: change,
2473
+ finalAmt: target,
2474
+ isDeposit: change.gt(0)
2475
+ };
2476
+ });
2477
+ const sumChanges = changes.reduce((sum, c) => sum.plus(c.changeAmt.toString()), Web3Number.fromWei("0", this.decimals()));
2478
+ const sumFinal = changes.reduce((sum, c) => sum.plus(c.finalAmt.toString()), Web3Number.fromWei("0", this.decimals()));
2479
+ const hasChanges = changes.some((c) => !c.changeAmt.eq(0));
2480
+ if (!sumChanges.eq(0)) throw new Error("Sum of changes must be zero");
2481
+ if (!sumFinal.eq(totalAssets)) throw new Error("Sum of final amounts must equal total assets");
2482
+ if (!hasChanges) throw new Error("No changes required");
2483
+ const finalPools = pools.map((p) => {
2484
+ const target = targetAmounts[p.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
2485
+ return {
2486
+ ...p,
2487
+ amount: target,
2488
+ usdValue: Web3Number.fromWei("0", this.decimals())
2489
+ };
2490
+ });
2491
+ return {
2492
+ changes,
2493
+ finalPools,
2494
+ isAnyPoolOverMaxWeight
2495
+ };
2496
+ }
2497
+ /**
2498
+ * Creates a rebalance Call object for the strategy contract
2499
+ * @param pools - Array of pool information including IDs, weights, amounts, APYs and utilization
2500
+ * @returns Populated contract call for rebalance
2501
+ */
2502
+ async getRebalanceCall(pools, isOverWeightAdjustment) {
2503
+ const actions = [];
2504
+ pools.sort((a, b) => b.isDeposit ? -1 : 1);
2505
+ console.log("pools", pools);
2506
+ pools.forEach((p) => {
2507
+ if (p.changeAmt.eq(0)) return null;
2508
+ actions.push({
2509
+ pool_id: p.pool_id.address,
2510
+ feature: new CairoCustomEnum(p.isDeposit ? { DEPOSIT: {} } : { WITHDRAW: {} }),
2511
+ token: this.asset().address,
2512
+ amount: uint2562.bnToUint256(p.changeAmt.multipliedBy(p.isDeposit ? 1 : -1).toWei())
2513
+ });
2514
+ });
2515
+ if (actions.length === 0) return null;
2516
+ if (isOverWeightAdjustment) {
2517
+ return this.contract.populate("rebalance_weights", [actions]);
2518
+ }
2519
+ return this.contract.populate("rebalance", [actions]);
2520
+ }
2521
+ async getInvestmentFlows(pools) {
2522
+ const netYield = this.netAPYGivenPools(pools);
2523
+ const baseFlow = {
2524
+ title: "Deposit $1000",
2525
+ subItems: [`Net yield: ${(netYield * 100).toFixed(2)}%`],
2526
+ linkedFlows: []
2527
+ };
2528
+ pools.forEach((p) => {
2529
+ if (p.amount.eq(0)) return;
2530
+ const flow = {
2531
+ title: `${p.pool_name} - $${(p.current_weight * 1e3).toFixed(2)}`,
2532
+ subItems: [
2533
+ `APY: ${(p.APY.netApy * 100).toFixed(2)}%`,
2534
+ `Weight: ${(p.current_weight * 100).toFixed(2)}% / ${(p.max_weight * 100).toFixed(2)}%`
2535
+ ],
2536
+ linkedFlows: []
2537
+ };
2538
+ baseFlow.linkedFlows.push(flow);
2539
+ });
2540
+ return [baseFlow];
2541
+ }
2542
+ };
2543
+ var _description = "Automatically diversify {{TOKEN}} holdings into different Vesu pools while reducing risk and maximizing yield. Defi spring STRK Rewards are auto-compounded as well.";
2544
+ var _protocol = { name: "Vesu", logo: "https://static-assets-8zct.onrender.com/integrations/vesu/logo.png" };
2545
+ var _riskFactor = [
2546
+ { type: "SMART_CONTRACT_RISK" /* SMART_CONTRACT_RISK */, value: 0.5, weight: 25 },
2547
+ { type: "TECHNICAL_RISK" /* TECHNICAL_RISK */, value: 0.5, weight: 25 },
2548
+ { type: "COUNTERPARTY_RISK" /* COUNTERPARTY_RISK */, value: 1, weight: 50 }
2549
+ ];
2550
+ var VesuRebalanceStrategies = [{
2551
+ name: "Vesu STRK",
2552
+ description: _description.replace("{{TOKEN}}", "STRK"),
2553
+ address: ContractAddr.from("0xeeb729d554ae486387147b13a9c8871bc7991d454e8b5ff570d4bf94de71e1"),
2554
+ type: "ERC4626",
2555
+ depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "STRK")],
2556
+ protocols: [_protocol],
2557
+ maxTVL: Web3Number.fromWei("0", 18),
2558
+ risk: {
2559
+ riskFactor: _riskFactor,
2560
+ netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / 100
2561
+ }
2562
+ }];
2563
+ export {
2564
+ AutoCompounderSTRK,
2565
+ ContractAddr,
2566
+ FatalError,
2567
+ Global,
2568
+ ILending,
2569
+ Initializable,
2570
+ MarginType,
2571
+ Network,
2572
+ Pragma,
2573
+ Pricer,
2574
+ PricerFromApi,
2575
+ RiskType,
2576
+ VesuRebalance,
2577
+ VesuRebalanceStrategies,
2578
+ Web3Number,
2579
+ ZkLend,
2580
+ getMainnetConfig,
2581
+ logger
2582
+ };