@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.
package/dist/index.mjs CHANGED
@@ -1,10 +1,3 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
1
  // src/modules/pricer.ts
9
2
  import axios2 from "axios";
10
3
 
@@ -25,7 +18,14 @@ var FatalError = class extends Error {
25
18
  this.name = "FatalError";
26
19
  }
27
20
  };
28
- var tokens = [];
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
29
  var Global = class {
30
30
  static fatalError(message, err) {
31
31
  logger.error(message);
@@ -38,6 +38,9 @@ var Global = class {
38
38
  logger.error(`${url}: ${message}`);
39
39
  console.error(err);
40
40
  }
41
+ static getDefaultTokens() {
42
+ return tokens;
43
+ }
41
44
  static async getTokens() {
42
45
  if (tokens.length) return tokens;
43
46
  const data = await axios.get("https://starknet.api.avnu.fi/v1/starknet/tokens");
@@ -51,6 +54,7 @@ var Global = class {
51
54
  symbol: token.symbol,
52
55
  address: token.address,
53
56
  decimals: token.decimals,
57
+ logo: token.logoUri,
54
58
  coingeckId: token.extensions.coingeckoId
55
59
  });
56
60
  });
@@ -79,10 +83,12 @@ var Web3Number = class _Web3Number extends BigNumber {
79
83
  return this.mul(10 ** this.decimals).toFixed(0);
80
84
  }
81
85
  multipliedBy(value) {
82
- return new _Web3Number(this.mul(value).toString(), this.decimals);
86
+ let _value = Number(value).toFixed(6);
87
+ return new _Web3Number(this.mul(_value).toString(), this.decimals);
83
88
  }
84
89
  dividedBy(value) {
85
- return new _Web3Number(this.div(value).toString(), this.decimals);
90
+ let _value = Number(value).toFixed(6);
91
+ return new _Web3Number(this.div(_value).toString(), this.decimals);
86
92
  }
87
93
  plus(value) {
88
94
  return new _Web3Number(this.add(value).toString(), this.decimals);
@@ -128,11 +134,22 @@ var ContractAddr = class _ContractAddr {
128
134
  }
129
135
  };
130
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
+
131
148
  // src/modules/pricer.ts
132
- var CoinMarketCap = __require("coinmarketcap-api");
133
- var Pricer = class {
149
+ var Pricer = class extends PricerBase {
150
+ // e.g. ETH/USDC
134
151
  constructor(config, tokens2) {
135
- this.tokens = [];
152
+ super(config, tokens2);
136
153
  this.prices = {};
137
154
  // code populates this map during runtime to determine which method to use for a given token
138
155
  // The method set will be the first one to try after first attempt
@@ -142,11 +159,6 @@ var Pricer = class {
142
159
  */
143
160
  this.PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
144
161
  this.EKUBO_API = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8";
145
- // e.g. ETH/USDC
146
- // backup oracle001
147
- this.client = new CoinMarketCap(process.env.COINMARKETCAP_KEY);
148
- this.config = config;
149
- this.tokens = tokens2;
150
162
  }
151
163
  isReady() {
152
164
  const allPricesExist = Object.keys(this.prices).length === this.tokens.length;
@@ -188,10 +200,10 @@ var Pricer = class {
188
200
  assertNotStale(timestamp, tokenName) {
189
201
  Global.assert(!this.isStale(timestamp, tokenName), `Price of ${tokenName} is stale`);
190
202
  }
191
- async getPrice(tokenName) {
192
- Global.assert(this.prices[tokenName], `Price of ${tokenName} not found`);
193
- this.assertNotStale(this.prices[tokenName].timestamp, tokenName);
194
- return this.prices[tokenName];
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];
195
207
  }
196
208
  _loadPrices(onUpdate = () => {
197
209
  }) {
@@ -278,10 +290,7 @@ var Pricer = class {
278
290
  return Number(data.data.amount);
279
291
  }
280
292
  async _getPriceCoinMarketCap(token) {
281
- const result = await this.client.getQuotes({ symbol: token.symbol });
282
- if (result.data)
283
- return result.data[token.symbol].quote.USD.price;
284
- throw new Error(result);
293
+ throw new Error("Not implemented");
285
294
  }
286
295
  async _getPriceEkubo(token, amountIn = new Web3Number(1, token.decimals), retry = 0) {
287
296
  const url = this.EKUBO_API.replace("{{TOKEN_ADDRESS}}", token.address).replace("{{AMOUNT}}", amountIn.toWei());
@@ -475,6 +484,7 @@ var _ZkLend = class _ZkLend extends ILending {
475
484
  name: pool.token.name,
476
485
  symbol: pool.token.symbol,
477
486
  address: savedTokenInfo?.address || "",
487
+ logo: "",
478
488
  decimals: pool.token.decimals,
479
489
  borrowFactor: Web3Number.fromWei(pool.borrow_factor.value, pool.borrow_factor.decimals),
480
490
  collareralFactor
@@ -584,8 +594,72 @@ var _ZkLend = class _ZkLend extends ILending {
584
594
  _ZkLend.POOLS_URL = "https://app.zklend.com/api/pools";
585
595
  var ZkLend = _ZkLend;
586
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
+
587
652
  // src/interfaces/common.ts
588
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 || {});
589
663
  var Network = /* @__PURE__ */ ((Network2) => {
590
664
  Network2["mainnet"] = "mainnet";
591
665
  Network2["sepolia"] = "sepolia";
@@ -681,231 +755,1879 @@ var AutoCompounderSTRK = class {
681
755
  }
682
756
  };
683
757
 
684
- // src/notifs/telegram.ts
685
- import TelegramBot from "node-telegram-bot-api";
686
- var TelegramNotif = class {
687
- constructor(token, shouldPoll) {
688
- this.subscribers = [
689
- // '6820228303',
690
- "1505578076",
691
- // '5434736198', // maaza
692
- "1356705582",
693
- // langs
694
- "1388729514",
695
- // hwashere
696
- "6020162572",
697
- //minato
698
- "985902592"
699
- ];
700
- this.bot = new TelegramBot(token, { polling: shouldPoll });
701
- }
702
- // listen to start msgs, register chatId and send registered msg
703
- activateChatBot() {
704
- this.bot.on("message", (msg) => {
705
- const chatId = msg.chat.id;
706
- let text = msg.text.toLowerCase().trim();
707
- logger.verbose(`Tg: IncomingMsg: ID: ${chatId}, msg: ${text}`);
708
- if (text == "start") {
709
- this.bot.sendMessage(chatId, "Registered");
710
- this.subscribers.push(chatId);
711
- logger.verbose(`Tg: New subscriber: ${chatId}`);
712
- } else {
713
- this.bot.sendMessage(chatId, "Unrecognized command. Supported commands: start");
714
- }
715
- });
716
- }
717
- // send a given msg to all registered users
718
- sendMessage(msg) {
719
- logger.verbose(`Tg: Sending message: ${msg}`);
720
- for (let chatId of this.subscribers) {
721
- this.bot.sendMessage(chatId, msg).catch((err) => {
722
- logger.error(`Tg: Error sending msg to ${chatId}`);
723
- logger.error(`Tg: Error sending message: ${err.message}`);
724
- }).then(() => {
725
- logger.verbose(`Tg: Message sent to ${chatId}`);
726
- });
727
- }
728
- }
729
- };
730
-
731
- // src/utils/store.ts
732
- import fs, { readFileSync, writeFileSync } from "fs";
733
- import { Account, constants } from "starknet";
734
- import * as crypto2 from "crypto";
735
-
736
- // src/utils/encrypt.ts
737
- import * as crypto from "crypto";
738
- var PasswordJsonCryptoUtil = class {
739
- constructor() {
740
- this.algorithm = "aes-256-gcm";
741
- this.keyLength = 32;
742
- // 256 bits
743
- this.saltLength = 16;
744
- // 128 bits
745
- this.ivLength = 12;
746
- // 96 bits for GCM
747
- this.tagLength = 16;
748
- // 128 bits
749
- this.pbkdf2Iterations = 1e5;
750
- }
751
- // Number of iterations for PBKDF2
752
- deriveKey(password, salt) {
753
- return crypto.pbkdf2Sync(password, salt, this.pbkdf2Iterations, this.keyLength, "sha256");
754
- }
755
- encrypt(data, password) {
756
- const jsonString = JSON.stringify(data);
757
- const salt = crypto.randomBytes(this.saltLength);
758
- const iv = crypto.randomBytes(this.ivLength);
759
- const key = this.deriveKey(password, salt);
760
- const cipher = crypto.createCipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
761
- let encrypted = cipher.update(jsonString, "utf8", "hex");
762
- encrypted += cipher.final("hex");
763
- const tag = cipher.getAuthTag();
764
- return Buffer.concat([salt, iv, tag, Buffer.from(encrypted, "hex")]).toString("base64");
765
- }
766
- decrypt(encryptedData, password) {
767
- const data = Buffer.from(encryptedData, "base64");
768
- const salt = data.subarray(0, this.saltLength);
769
- const iv = data.subarray(this.saltLength, this.saltLength + this.ivLength);
770
- const tag = data.subarray(this.saltLength + this.ivLength, this.saltLength + this.ivLength + this.tagLength);
771
- const encrypted = data.subarray(this.saltLength + this.ivLength + this.tagLength);
772
- const key = this.deriveKey(password, salt);
773
- const decipher = crypto.createDecipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
774
- decipher.setAuthTag(tag);
775
- try {
776
- let decrypted = decipher.update(encrypted.toString("hex"), "hex", "utf8");
777
- decrypted += decipher.final("utf8");
778
- return JSON.parse(decrypted);
779
- } catch (error) {
780
- throw new Error("Decryption failed. This could be due to an incorrect password or corrupted data.");
781
- }
782
- }
783
- };
784
-
785
- // src/utils/store.ts
786
- function getDefaultStoreConfig(network) {
787
- if (!process.env.HOME) {
788
- throw new Error("StoreConfig: HOME environment variable not found");
789
- }
790
- return {
791
- SECRET_FILE_FOLDER: `${process.env.HOME}/.starknet-store`,
792
- NETWORK: network,
793
- ACCOUNTS_FILE_NAME: "accounts.json",
794
- PASSWORD: crypto2.randomBytes(16).toString("hex")
795
- };
796
- }
797
- var Store = class _Store {
798
- constructor(config, storeConfig) {
799
- this.encryptor = new PasswordJsonCryptoUtil();
800
- this.config = config;
801
- const defaultStoreConfig = getDefaultStoreConfig(config.network);
802
- if (!storeConfig.PASSWORD) {
803
- _Store.logPassword(defaultStoreConfig.PASSWORD);
804
- }
805
- this.storeConfig = {
806
- ...defaultStoreConfig,
807
- ...storeConfig
808
- };
809
- _Store.ensureFolder(this.storeConfig.SECRET_FILE_FOLDER);
810
- }
811
- static logPassword(password) {
812
- logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
813
- logger.warn(`Generated a random password for store`);
814
- logger.warn(`\u26A0\uFE0F Password: ${password}`);
815
- logger.warn(`This not stored anywhere, please you backup this password for future use`);
816
- logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
817
- }
818
- getAccount(accountKey, txVersion = constants.TRANSACTION_VERSION.V2) {
819
- const accounts = this.loadAccounts();
820
- logger.verbose(`nAccounts loaded for network: ${Object.keys(accounts).length}`);
821
- const data = accounts[accountKey];
822
- if (!data) {
823
- throw new Error(`Account not found: ${accountKey}`);
824
- }
825
- logger.verbose(`Account loaded: ${accountKey} from network: ${this.config.network}`);
826
- logger.verbose(`Address: ${data.address}`);
827
- const acc = new Account(this.config.provider, data.address, data.pk, void 0, txVersion);
828
- return acc;
829
- }
830
- addAccount(accountKey, address, pk) {
831
- const allAccounts = this.getAllAccounts();
832
- if (!allAccounts[this.config.network]) {
833
- allAccounts[this.config.network] = {};
834
- }
835
- allAccounts[this.config.network][accountKey] = {
836
- address,
837
- pk
838
- };
839
- const encryptedData = this.encryptor.encrypt(allAccounts, this.storeConfig.PASSWORD);
840
- writeFileSync(this.getAccountFilePath(), encryptedData);
841
- logger.verbose(`Account added: ${accountKey} to network: ${this.config.network}`);
842
- }
843
- getAccountFilePath() {
844
- const path = `${this.storeConfig.SECRET_FILE_FOLDER}/${this.storeConfig.ACCOUNTS_FILE_NAME}`;
845
- logger.verbose(`Path: ${path}`);
846
- return path;
847
- }
848
- getAllAccounts() {
849
- const PATH = this.getAccountFilePath();
850
- if (!fs.existsSync(PATH)) {
851
- logger.verbose(`Accounts: files doesnt exist`);
852
- return {};
853
- }
854
- let encryptedData = readFileSync(PATH, {
855
- encoding: "utf-8"
856
- });
857
- let data = this.encryptor.decrypt(encryptedData, this.storeConfig.PASSWORD);
858
- return data;
859
- }
860
- /**
861
- * @description Load all accounts of the network
862
- * @returns NetworkAccounts
863
- */
864
- loadAccounts() {
865
- const allData = this.getAllAccounts();
866
- logger.verbose(`Accounts loaded for network: ${this.config.network}`);
867
- if (!allData[this.config.network]) {
868
- allData[this.config.network] = {};
869
- }
870
- return allData[this.config.network];
871
- }
872
- /**
873
- * @description List all accountKeys of the network
874
- * @returns string[]
875
- */
876
- listAccounts() {
877
- return Object.keys(this.loadAccounts());
878
- }
879
- static ensureFolder(folder) {
880
- if (!fs.existsSync(folder)) {
881
- fs.mkdirSync(folder, { recursive: true });
882
- }
883
- if (!fs.existsSync(`${folder}`)) {
884
- throw new Error(`Store folder not found: ${folder}`);
885
- }
886
- }
887
- };
758
+ // src/strategies/vesu-rebalance.ts
759
+ import { CairoCustomEnum, Contract as Contract3, num as num2, uint256 as uint2562 } from "starknet";
888
760
 
889
- // src/node/pricer-redis.ts
890
- import { createClient } from "redis";
891
- var PricerRedis = class extends Pricer {
892
- constructor(config, tokens2) {
893
- super(config, tokens2);
894
- this.redisClient = null;
895
- }
896
- /** Reads prices from Pricer._loadPrices and uses a callback to set prices in redis */
897
- async startWithRedis(redisUrl) {
898
- await this.initRedis(redisUrl);
899
- logger.info(`Starting Pricer with Redis`);
900
- this._loadPrices(this._setRedisPrices.bind(this));
901
- setInterval(() => {
902
- this._loadPrices(this._setRedisPrices.bind(this));
903
- }, 3e4);
904
- }
905
- async close() {
906
- if (this.redisClient) {
907
- await this.redisClient.disconnect();
908
- }
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
+
2564
+ // src/notifs/telegram.ts
2565
+ import TelegramBot from "node-telegram-bot-api";
2566
+ var TelegramNotif = class {
2567
+ constructor(token, shouldPoll) {
2568
+ this.subscribers = [
2569
+ // '6820228303',
2570
+ "1505578076",
2571
+ // '5434736198', // maaza
2572
+ "1356705582",
2573
+ // langs
2574
+ "1388729514",
2575
+ // hwashere
2576
+ "6020162572",
2577
+ //minato
2578
+ "985902592"
2579
+ ];
2580
+ this.bot = new TelegramBot(token, { polling: shouldPoll });
2581
+ }
2582
+ // listen to start msgs, register chatId and send registered msg
2583
+ activateChatBot() {
2584
+ this.bot.on("message", (msg) => {
2585
+ const chatId = msg.chat.id;
2586
+ let text = msg.text.toLowerCase().trim();
2587
+ logger.verbose(`Tg: IncomingMsg: ID: ${chatId}, msg: ${text}`);
2588
+ if (text == "start") {
2589
+ this.bot.sendMessage(chatId, "Registered");
2590
+ this.subscribers.push(chatId);
2591
+ logger.verbose(`Tg: New subscriber: ${chatId}`);
2592
+ } else {
2593
+ this.bot.sendMessage(chatId, "Unrecognized command. Supported commands: start");
2594
+ }
2595
+ });
2596
+ }
2597
+ // send a given msg to all registered users
2598
+ sendMessage(msg) {
2599
+ logger.verbose(`Tg: Sending message: ${msg}`);
2600
+ for (let chatId of this.subscribers) {
2601
+ this.bot.sendMessage(chatId, msg).catch((err) => {
2602
+ logger.error(`Tg: Error sending msg to ${chatId}`);
2603
+ logger.error(`Tg: Error sending message: ${err.message}`);
2604
+ }).then(() => {
2605
+ logger.verbose(`Tg: Message sent to ${chatId}`);
2606
+ });
2607
+ }
2608
+ }
2609
+ };
2610
+
2611
+ // src/node/pricer-redis.ts
2612
+ import { createClient } from "redis";
2613
+ var PricerRedis = class extends Pricer {
2614
+ constructor(config, tokens2) {
2615
+ super(config, tokens2);
2616
+ this.redisClient = null;
2617
+ }
2618
+ /** Reads prices from Pricer._loadPrices and uses a callback to set prices in redis */
2619
+ async startWithRedis(redisUrl) {
2620
+ await this.initRedis(redisUrl);
2621
+ logger.info(`Starting Pricer with Redis`);
2622
+ this._loadPrices(this._setRedisPrices.bind(this));
2623
+ setInterval(() => {
2624
+ this._loadPrices(this._setRedisPrices.bind(this));
2625
+ }, 3e4);
2626
+ }
2627
+ async close() {
2628
+ if (this.redisClient) {
2629
+ await this.redisClient.disconnect();
2630
+ }
909
2631
  }
910
2632
  async initRedis(redisUrl) {
911
2633
  logger.info(`Initialising Redis Client`);
@@ -942,6 +2664,164 @@ var PricerRedis = class extends Pricer {
942
2664
  return priceInfo;
943
2665
  }
944
2666
  };
2667
+
2668
+ // src/utils/store.ts
2669
+ import fs, { readFileSync, writeFileSync } from "fs";
2670
+ import { Account, constants } from "starknet";
2671
+ import * as crypto2 from "crypto";
2672
+
2673
+ // src/utils/encrypt.ts
2674
+ import * as crypto from "crypto";
2675
+ var PasswordJsonCryptoUtil = class {
2676
+ constructor() {
2677
+ this.algorithm = "aes-256-gcm";
2678
+ this.keyLength = 32;
2679
+ // 256 bits
2680
+ this.saltLength = 16;
2681
+ // 128 bits
2682
+ this.ivLength = 12;
2683
+ // 96 bits for GCM
2684
+ this.tagLength = 16;
2685
+ // 128 bits
2686
+ this.pbkdf2Iterations = 1e5;
2687
+ }
2688
+ // Number of iterations for PBKDF2
2689
+ deriveKey(password, salt) {
2690
+ return crypto.pbkdf2Sync(password, salt, this.pbkdf2Iterations, this.keyLength, "sha256");
2691
+ }
2692
+ encrypt(data, password) {
2693
+ const jsonString = JSON.stringify(data);
2694
+ const salt = crypto.randomBytes(this.saltLength);
2695
+ const iv = crypto.randomBytes(this.ivLength);
2696
+ const key = this.deriveKey(password, salt);
2697
+ const cipher = crypto.createCipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
2698
+ let encrypted = cipher.update(jsonString, "utf8", "hex");
2699
+ encrypted += cipher.final("hex");
2700
+ const tag = cipher.getAuthTag();
2701
+ return Buffer.concat([salt, iv, tag, Buffer.from(encrypted, "hex")]).toString("base64");
2702
+ }
2703
+ decrypt(encryptedData, password) {
2704
+ const data = Buffer.from(encryptedData, "base64");
2705
+ const salt = data.subarray(0, this.saltLength);
2706
+ const iv = data.subarray(this.saltLength, this.saltLength + this.ivLength);
2707
+ const tag = data.subarray(this.saltLength + this.ivLength, this.saltLength + this.ivLength + this.tagLength);
2708
+ const encrypted = data.subarray(this.saltLength + this.ivLength + this.tagLength);
2709
+ const key = this.deriveKey(password, salt);
2710
+ const decipher = crypto.createDecipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
2711
+ decipher.setAuthTag(tag);
2712
+ try {
2713
+ let decrypted = decipher.update(encrypted.toString("hex"), "hex", "utf8");
2714
+ decrypted += decipher.final("utf8");
2715
+ return JSON.parse(decrypted);
2716
+ } catch (error) {
2717
+ throw new Error("Decryption failed. This could be due to an incorrect password or corrupted data.");
2718
+ }
2719
+ }
2720
+ };
2721
+
2722
+ // src/utils/store.ts
2723
+ function getDefaultStoreConfig(network) {
2724
+ if (!process.env.HOME) {
2725
+ throw new Error("StoreConfig: HOME environment variable not found");
2726
+ }
2727
+ return {
2728
+ SECRET_FILE_FOLDER: `${process.env.HOME}/.starknet-store`,
2729
+ NETWORK: network,
2730
+ ACCOUNTS_FILE_NAME: "accounts.json",
2731
+ PASSWORD: crypto2.randomBytes(16).toString("hex")
2732
+ };
2733
+ }
2734
+ var Store = class _Store {
2735
+ constructor(config, storeConfig) {
2736
+ this.encryptor = new PasswordJsonCryptoUtil();
2737
+ this.config = config;
2738
+ const defaultStoreConfig = getDefaultStoreConfig(config.network);
2739
+ if (!storeConfig.PASSWORD) {
2740
+ _Store.logPassword(defaultStoreConfig.PASSWORD);
2741
+ }
2742
+ this.storeConfig = {
2743
+ ...defaultStoreConfig,
2744
+ ...storeConfig
2745
+ };
2746
+ _Store.ensureFolder(this.storeConfig.SECRET_FILE_FOLDER);
2747
+ }
2748
+ static logPassword(password) {
2749
+ logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
2750
+ logger.warn(`Generated a random password for store`);
2751
+ logger.warn(`\u26A0\uFE0F Password: ${password}`);
2752
+ logger.warn(`This not stored anywhere, please you backup this password for future use`);
2753
+ logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
2754
+ }
2755
+ getAccount(accountKey, txVersion = constants.TRANSACTION_VERSION.V2) {
2756
+ const accounts = this.loadAccounts();
2757
+ logger.verbose(`nAccounts loaded for network: ${Object.keys(accounts).length}`);
2758
+ const data = accounts[accountKey];
2759
+ if (!data) {
2760
+ throw new Error(`Account not found: ${accountKey}`);
2761
+ }
2762
+ logger.verbose(`Account loaded: ${accountKey} from network: ${this.config.network}`);
2763
+ logger.verbose(`Address: ${data.address}`);
2764
+ const acc = new Account(this.config.provider, data.address, data.pk, void 0, txVersion);
2765
+ return acc;
2766
+ }
2767
+ addAccount(accountKey, address, pk) {
2768
+ const allAccounts = this.getAllAccounts();
2769
+ if (!allAccounts[this.config.network]) {
2770
+ allAccounts[this.config.network] = {};
2771
+ }
2772
+ allAccounts[this.config.network][accountKey] = {
2773
+ address,
2774
+ pk
2775
+ };
2776
+ const encryptedData = this.encryptor.encrypt(allAccounts, this.storeConfig.PASSWORD);
2777
+ writeFileSync(this.getAccountFilePath(), encryptedData);
2778
+ logger.verbose(`Account added: ${accountKey} to network: ${this.config.network}`);
2779
+ }
2780
+ getAccountFilePath() {
2781
+ const path = `${this.storeConfig.SECRET_FILE_FOLDER}/${this.storeConfig.ACCOUNTS_FILE_NAME}`;
2782
+ logger.verbose(`Path: ${path}`);
2783
+ return path;
2784
+ }
2785
+ getAllAccounts() {
2786
+ const PATH = this.getAccountFilePath();
2787
+ if (!fs.existsSync(PATH)) {
2788
+ logger.verbose(`Accounts: files doesnt exist`);
2789
+ return {};
2790
+ }
2791
+ let encryptedData = readFileSync(PATH, {
2792
+ encoding: "utf-8"
2793
+ });
2794
+ let data = this.encryptor.decrypt(encryptedData, this.storeConfig.PASSWORD);
2795
+ return data;
2796
+ }
2797
+ /**
2798
+ * @description Load all accounts of the network
2799
+ * @returns NetworkAccounts
2800
+ */
2801
+ loadAccounts() {
2802
+ const allData = this.getAllAccounts();
2803
+ logger.verbose(`Accounts loaded for network: ${this.config.network}`);
2804
+ if (!allData[this.config.network]) {
2805
+ allData[this.config.network] = {};
2806
+ }
2807
+ return allData[this.config.network];
2808
+ }
2809
+ /**
2810
+ * @description List all accountKeys of the network
2811
+ * @returns string[]
2812
+ */
2813
+ listAccounts() {
2814
+ return Object.keys(this.loadAccounts());
2815
+ }
2816
+ static ensureFolder(folder) {
2817
+ if (!fs.existsSync(folder)) {
2818
+ fs.mkdirSync(folder, { recursive: true });
2819
+ }
2820
+ if (!fs.existsSync(`${folder}`)) {
2821
+ throw new Error(`Store folder not found: ${folder}`);
2822
+ }
2823
+ }
2824
+ };
945
2825
  export {
946
2826
  AutoCompounderSTRK,
947
2827
  ContractAddr,
@@ -954,11 +2834,16 @@ export {
954
2834
  PasswordJsonCryptoUtil,
955
2835
  Pragma,
956
2836
  Pricer,
2837
+ PricerFromApi,
957
2838
  PricerRedis,
2839
+ RiskType,
958
2840
  Store,
959
2841
  TelegramNotif,
2842
+ VesuRebalance,
2843
+ VesuRebalanceStrategies,
960
2844
  Web3Number,
961
2845
  ZkLend,
2846
+ assert,
962
2847
  getDefaultStoreConfig,
963
2848
  getMainnetConfig,
964
2849
  logger