@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.js CHANGED
@@ -41,11 +41,16 @@ __export(src_exports, {
41
41
  PasswordJsonCryptoUtil: () => PasswordJsonCryptoUtil,
42
42
  Pragma: () => Pragma,
43
43
  Pricer: () => Pricer,
44
+ PricerFromApi: () => PricerFromApi,
44
45
  PricerRedis: () => PricerRedis,
46
+ RiskType: () => RiskType,
45
47
  Store: () => Store,
46
48
  TelegramNotif: () => TelegramNotif,
49
+ VesuRebalance: () => VesuRebalance,
50
+ VesuRebalanceStrategies: () => VesuRebalanceStrategies,
47
51
  Web3Number: () => Web3Number,
48
52
  ZkLend: () => ZkLend,
53
+ assert: () => assert,
49
54
  getDefaultStoreConfig: () => getDefaultStoreConfig,
50
55
  getMainnetConfig: () => getMainnetConfig,
51
56
  logger: () => logger
@@ -72,7 +77,14 @@ var FatalError = class extends Error {
72
77
  this.name = "FatalError";
73
78
  }
74
79
  };
75
- var tokens = [];
80
+ var tokens = [{
81
+ name: "Starknet",
82
+ symbol: "STRK",
83
+ logo: "https://assets.coingecko.com/coins/images/26433/small/starknet.png",
84
+ address: "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
85
+ decimals: 18,
86
+ coingeckId: "starknet"
87
+ }];
76
88
  var Global = class {
77
89
  static fatalError(message, err) {
78
90
  logger.error(message);
@@ -85,6 +97,9 @@ var Global = class {
85
97
  logger.error(`${url}: ${message}`);
86
98
  console.error(err);
87
99
  }
100
+ static getDefaultTokens() {
101
+ return tokens;
102
+ }
88
103
  static async getTokens() {
89
104
  if (tokens.length) return tokens;
90
105
  const data = await import_axios.default.get("https://starknet.api.avnu.fi/v1/starknet/tokens");
@@ -98,6 +113,7 @@ var Global = class {
98
113
  symbol: token.symbol,
99
114
  address: token.address,
100
115
  decimals: token.decimals,
116
+ logo: token.logoUri,
101
117
  coingeckId: token.extensions.coingeckoId
102
118
  });
103
119
  });
@@ -126,10 +142,12 @@ var Web3Number = class _Web3Number extends import_bignumber.default {
126
142
  return this.mul(10 ** this.decimals).toFixed(0);
127
143
  }
128
144
  multipliedBy(value) {
129
- return new _Web3Number(this.mul(value).toString(), this.decimals);
145
+ let _value = Number(value).toFixed(6);
146
+ return new _Web3Number(this.mul(_value).toString(), this.decimals);
130
147
  }
131
148
  dividedBy(value) {
132
- return new _Web3Number(this.div(value).toString(), this.decimals);
149
+ let _value = Number(value).toFixed(6);
150
+ return new _Web3Number(this.div(_value).toString(), this.decimals);
133
151
  }
134
152
  plus(value) {
135
153
  return new _Web3Number(this.add(value).toString(), this.decimals);
@@ -175,11 +193,22 @@ var ContractAddr = class _ContractAddr {
175
193
  }
176
194
  };
177
195
 
196
+ // src/modules/pricerBase.ts
197
+ var PricerBase = class {
198
+ constructor(config, tokens2) {
199
+ this.config = config;
200
+ this.tokens = tokens2;
201
+ }
202
+ async getPrice(tokenSymbol) {
203
+ throw new Error("Method not implemented");
204
+ }
205
+ };
206
+
178
207
  // src/modules/pricer.ts
179
- var CoinMarketCap = require("coinmarketcap-api");
180
- var Pricer = class {
208
+ var Pricer = class extends PricerBase {
209
+ // e.g. ETH/USDC
181
210
  constructor(config, tokens2) {
182
- this.tokens = [];
211
+ super(config, tokens2);
183
212
  this.prices = {};
184
213
  // code populates this map during runtime to determine which method to use for a given token
185
214
  // The method set will be the first one to try after first attempt
@@ -189,11 +218,6 @@ var Pricer = class {
189
218
  */
190
219
  this.PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
191
220
  this.EKUBO_API = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8";
192
- // e.g. ETH/USDC
193
- // backup oracle001
194
- this.client = new CoinMarketCap(process.env.COINMARKETCAP_KEY);
195
- this.config = config;
196
- this.tokens = tokens2;
197
221
  }
198
222
  isReady() {
199
223
  const allPricesExist = Object.keys(this.prices).length === this.tokens.length;
@@ -235,10 +259,10 @@ var Pricer = class {
235
259
  assertNotStale(timestamp, tokenName) {
236
260
  Global.assert(!this.isStale(timestamp, tokenName), `Price of ${tokenName} is stale`);
237
261
  }
238
- async getPrice(tokenName) {
239
- Global.assert(this.prices[tokenName], `Price of ${tokenName} not found`);
240
- this.assertNotStale(this.prices[tokenName].timestamp, tokenName);
241
- return this.prices[tokenName];
262
+ async getPrice(tokenSymbol) {
263
+ Global.assert(this.prices[tokenSymbol], `Price of ${tokenSymbol} not found`);
264
+ this.assertNotStale(this.prices[tokenSymbol].timestamp, tokenSymbol);
265
+ return this.prices[tokenSymbol];
242
266
  }
243
267
  _loadPrices(onUpdate = () => {
244
268
  }) {
@@ -325,10 +349,7 @@ var Pricer = class {
325
349
  return Number(data.data.amount);
326
350
  }
327
351
  async _getPriceCoinMarketCap(token) {
328
- const result = await this.client.getQuotes({ symbol: token.symbol });
329
- if (result.data)
330
- return result.data[token.symbol].quote.USD.price;
331
- throw new Error(result);
352
+ throw new Error("Not implemented");
332
353
  }
333
354
  async _getPriceEkubo(token, amountIn = new Web3Number(1, token.decimals), retry = 0) {
334
355
  const url = this.EKUBO_API.replace("{{TOKEN_ADDRESS}}", token.address).replace("{{AMOUNT}}", amountIn.toWei());
@@ -522,6 +543,7 @@ var _ZkLend = class _ZkLend extends ILending {
522
543
  name: pool.token.name,
523
544
  symbol: pool.token.symbol,
524
545
  address: savedTokenInfo?.address || "",
546
+ logo: "",
525
547
  decimals: pool.token.decimals,
526
548
  borrowFactor: Web3Number.fromWei(pool.borrow_factor.value, pool.borrow_factor.decimals),
527
549
  collareralFactor
@@ -631,8 +653,72 @@ var _ZkLend = class _ZkLend extends ILending {
631
653
  _ZkLend.POOLS_URL = "https://app.zklend.com/api/pools";
632
654
  var ZkLend = _ZkLend;
633
655
 
656
+ // src/modules/pricer-from-api.ts
657
+ var import_axios4 = __toESM(require("axios"));
658
+ var PricerFromApi = class extends PricerBase {
659
+ constructor(config, tokens2) {
660
+ super(config, tokens2);
661
+ }
662
+ async getPrice(tokenSymbol) {
663
+ try {
664
+ return await this.getPriceFromMyAPI(tokenSymbol);
665
+ } catch (e) {
666
+ logger.warn("getPriceFromMyAPI error", e);
667
+ }
668
+ logger.log("getPrice coinbase", tokenSymbol);
669
+ let retry = 0;
670
+ const MAX_RETRIES = 5;
671
+ for (retry = 1; retry < MAX_RETRIES + 1; retry++) {
672
+ try {
673
+ const priceInfo = await import_axios4.default.get(
674
+ `https://api.coinbase.com/v2/prices/${tokenSymbol}-USDT/spot`
675
+ );
676
+ if (!priceInfo) {
677
+ throw new Error("Failed to fetch price");
678
+ }
679
+ const data = await priceInfo.data;
680
+ const price = Number(data.data.amount);
681
+ return {
682
+ price,
683
+ timestamp: /* @__PURE__ */ new Date()
684
+ };
685
+ } catch (e) {
686
+ logger.warn("getPrice coinbase error", e, retry);
687
+ await new Promise((resolve) => setTimeout(resolve, retry * 1e3));
688
+ }
689
+ }
690
+ throw new Error(`Failed to fetch price for ${tokenSymbol}`);
691
+ }
692
+ async getPriceFromMyAPI(tokenSymbol) {
693
+ logger.verbose(`getPrice from redis: ${tokenSymbol}`);
694
+ const endpoint = "https://app.strkfarm.com";
695
+ const url = `${endpoint}/api/price/${tokenSymbol}`;
696
+ const priceInfoRes = await fetch(url);
697
+ const priceInfo = await priceInfoRes.json();
698
+ const now = /* @__PURE__ */ new Date();
699
+ const priceTime = new Date(priceInfo.timestamp);
700
+ if (now.getTime() - priceTime.getTime() > 9e5) {
701
+ throw new Error("Price is stale");
702
+ }
703
+ const price = Number(priceInfo.price);
704
+ return {
705
+ price,
706
+ timestamp: new Date(priceInfo.timestamp)
707
+ };
708
+ }
709
+ };
710
+
634
711
  // src/interfaces/common.ts
635
712
  var import_starknet3 = require("starknet");
713
+ var RiskType = /* @__PURE__ */ ((RiskType2) => {
714
+ RiskType2["MARKET_RISK"] = "MARKET_RISK";
715
+ RiskType2["IMPERMANENT_LOSS"] = "IMPERMANENT_LOSS";
716
+ RiskType2["LIQUIDITY_RISK"] = "LIQUIDITY_RISK";
717
+ RiskType2["SMART_CONTRACT_RISK"] = "SMART_CONTRACT_RISK";
718
+ RiskType2["TECHNICAL_RISK"] = "TECHNICAL_RISK";
719
+ RiskType2["COUNTERPARTY_RISK"] = "COUNTERPARTY_RISK";
720
+ return RiskType2;
721
+ })(RiskType || {});
636
722
  var Network = /* @__PURE__ */ ((Network2) => {
637
723
  Network2["mainnet"] = "mainnet";
638
724
  Network2["sepolia"] = "sepolia";
@@ -728,235 +814,1883 @@ var AutoCompounderSTRK = class {
728
814
  }
729
815
  };
730
816
 
731
- // src/notifs/telegram.ts
732
- var import_node_telegram_bot_api = __toESM(require("node-telegram-bot-api"));
733
- var TelegramNotif = class {
734
- constructor(token, shouldPoll) {
735
- this.subscribers = [
736
- // '6820228303',
737
- "1505578076",
738
- // '5434736198', // maaza
739
- "1356705582",
740
- // langs
741
- "1388729514",
742
- // hwashere
743
- "6020162572",
744
- //minato
745
- "985902592"
746
- ];
747
- this.bot = new import_node_telegram_bot_api.default(token, { polling: shouldPoll });
748
- }
749
- // listen to start msgs, register chatId and send registered msg
750
- activateChatBot() {
751
- this.bot.on("message", (msg) => {
752
- const chatId = msg.chat.id;
753
- let text = msg.text.toLowerCase().trim();
754
- logger.verbose(`Tg: IncomingMsg: ID: ${chatId}, msg: ${text}`);
755
- if (text == "start") {
756
- this.bot.sendMessage(chatId, "Registered");
757
- this.subscribers.push(chatId);
758
- logger.verbose(`Tg: New subscriber: ${chatId}`);
759
- } else {
760
- this.bot.sendMessage(chatId, "Unrecognized command. Supported commands: start");
761
- }
762
- });
763
- }
764
- // send a given msg to all registered users
765
- sendMessage(msg) {
766
- logger.verbose(`Tg: Sending message: ${msg}`);
767
- for (let chatId of this.subscribers) {
768
- this.bot.sendMessage(chatId, msg).catch((err) => {
769
- logger.error(`Tg: Error sending msg to ${chatId}`);
770
- logger.error(`Tg: Error sending message: ${err.message}`);
771
- }).then(() => {
772
- logger.verbose(`Tg: Message sent to ${chatId}`);
773
- });
774
- }
775
- }
776
- };
777
-
778
- // src/utils/store.ts
779
- var import_fs = __toESM(require("fs"));
817
+ // src/strategies/vesu-rebalance.ts
780
818
  var import_starknet5 = require("starknet");
781
- var crypto2 = __toESM(require("crypto"));
782
-
783
- // src/utils/encrypt.ts
784
- var crypto = __toESM(require("crypto"));
785
- var PasswordJsonCryptoUtil = class {
786
- constructor() {
787
- this.algorithm = "aes-256-gcm";
788
- this.keyLength = 32;
789
- // 256 bits
790
- this.saltLength = 16;
791
- // 128 bits
792
- this.ivLength = 12;
793
- // 96 bits for GCM
794
- this.tagLength = 16;
795
- // 128 bits
796
- this.pbkdf2Iterations = 1e5;
797
- }
798
- // Number of iterations for PBKDF2
799
- deriveKey(password, salt) {
800
- return crypto.pbkdf2Sync(password, salt, this.pbkdf2Iterations, this.keyLength, "sha256");
801
- }
802
- encrypt(data, password) {
803
- const jsonString = JSON.stringify(data);
804
- const salt = crypto.randomBytes(this.saltLength);
805
- const iv = crypto.randomBytes(this.ivLength);
806
- const key = this.deriveKey(password, salt);
807
- const cipher = crypto.createCipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
808
- let encrypted = cipher.update(jsonString, "utf8", "hex");
809
- encrypted += cipher.final("hex");
810
- const tag = cipher.getAuthTag();
811
- return Buffer.concat([salt, iv, tag, Buffer.from(encrypted, "hex")]).toString("base64");
812
- }
813
- decrypt(encryptedData, password) {
814
- const data = Buffer.from(encryptedData, "base64");
815
- const salt = data.subarray(0, this.saltLength);
816
- const iv = data.subarray(this.saltLength, this.saltLength + this.ivLength);
817
- const tag = data.subarray(this.saltLength + this.ivLength, this.saltLength + this.ivLength + this.tagLength);
818
- const encrypted = data.subarray(this.saltLength + this.ivLength + this.tagLength);
819
- const key = this.deriveKey(password, salt);
820
- const decipher = crypto.createDecipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
821
- decipher.setAuthTag(tag);
822
- try {
823
- let decrypted = decipher.update(encrypted.toString("hex"), "hex", "utf8");
824
- decrypted += decipher.final("utf8");
825
- return JSON.parse(decrypted);
826
- } catch (error) {
827
- throw new Error("Decryption failed. This could be due to an incorrect password or corrupted data.");
828
- }
829
- }
830
- };
831
-
832
- // src/utils/store.ts
833
- function getDefaultStoreConfig(network) {
834
- if (!process.env.HOME) {
835
- throw new Error("StoreConfig: HOME environment variable not found");
836
- }
837
- return {
838
- SECRET_FILE_FOLDER: `${process.env.HOME}/.starknet-store`,
839
- NETWORK: network,
840
- ACCOUNTS_FILE_NAME: "accounts.json",
841
- PASSWORD: crypto2.randomBytes(16).toString("hex")
842
- };
843
- }
844
- var Store = class _Store {
845
- constructor(config, storeConfig) {
846
- this.encryptor = new PasswordJsonCryptoUtil();
847
- this.config = config;
848
- const defaultStoreConfig = getDefaultStoreConfig(config.network);
849
- if (!storeConfig.PASSWORD) {
850
- _Store.logPassword(defaultStoreConfig.PASSWORD);
851
- }
852
- this.storeConfig = {
853
- ...defaultStoreConfig,
854
- ...storeConfig
855
- };
856
- _Store.ensureFolder(this.storeConfig.SECRET_FILE_FOLDER);
857
- }
858
- static logPassword(password) {
859
- logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
860
- logger.warn(`Generated a random password for store`);
861
- logger.warn(`\u26A0\uFE0F Password: ${password}`);
862
- logger.warn(`This not stored anywhere, please you backup this password for future use`);
863
- logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
864
- }
865
- getAccount(accountKey, txVersion = import_starknet5.constants.TRANSACTION_VERSION.V2) {
866
- const accounts = this.loadAccounts();
867
- logger.verbose(`nAccounts loaded for network: ${Object.keys(accounts).length}`);
868
- const data = accounts[accountKey];
869
- if (!data) {
870
- throw new Error(`Account not found: ${accountKey}`);
871
- }
872
- logger.verbose(`Account loaded: ${accountKey} from network: ${this.config.network}`);
873
- logger.verbose(`Address: ${data.address}`);
874
- const acc = new import_starknet5.Account(this.config.provider, data.address, data.pk, void 0, txVersion);
875
- return acc;
876
- }
877
- addAccount(accountKey, address, pk) {
878
- const allAccounts = this.getAllAccounts();
879
- if (!allAccounts[this.config.network]) {
880
- allAccounts[this.config.network] = {};
881
- }
882
- allAccounts[this.config.network][accountKey] = {
883
- address,
884
- pk
885
- };
886
- const encryptedData = this.encryptor.encrypt(allAccounts, this.storeConfig.PASSWORD);
887
- (0, import_fs.writeFileSync)(this.getAccountFilePath(), encryptedData);
888
- logger.verbose(`Account added: ${accountKey} to network: ${this.config.network}`);
889
- }
890
- getAccountFilePath() {
891
- const path = `${this.storeConfig.SECRET_FILE_FOLDER}/${this.storeConfig.ACCOUNTS_FILE_NAME}`;
892
- logger.verbose(`Path: ${path}`);
893
- return path;
894
- }
895
- getAllAccounts() {
896
- const PATH = this.getAccountFilePath();
897
- if (!import_fs.default.existsSync(PATH)) {
898
- logger.verbose(`Accounts: files doesnt exist`);
899
- return {};
900
- }
901
- let encryptedData = (0, import_fs.readFileSync)(PATH, {
902
- encoding: "utf-8"
903
- });
904
- let data = this.encryptor.decrypt(encryptedData, this.storeConfig.PASSWORD);
905
- return data;
906
- }
907
- /**
908
- * @description Load all accounts of the network
909
- * @returns NetworkAccounts
910
- */
911
- loadAccounts() {
912
- const allData = this.getAllAccounts();
913
- logger.verbose(`Accounts loaded for network: ${this.config.network}`);
914
- if (!allData[this.config.network]) {
915
- allData[this.config.network] = {};
916
- }
917
- return allData[this.config.network];
918
- }
919
- /**
920
- * @description List all accountKeys of the network
921
- * @returns string[]
922
- */
923
- listAccounts() {
924
- return Object.keys(this.loadAccounts());
925
- }
926
- static ensureFolder(folder) {
927
- if (!import_fs.default.existsSync(folder)) {
928
- import_fs.default.mkdirSync(folder, { recursive: true });
929
- }
930
- if (!import_fs.default.existsSync(`${folder}`)) {
931
- throw new Error(`Store folder not found: ${folder}`);
932
- }
933
- }
934
- };
935
819
 
936
- // src/node/pricer-redis.ts
937
- var import_redis = require("redis");
938
- var PricerRedis = class extends Pricer {
939
- constructor(config, tokens2) {
940
- super(config, tokens2);
941
- this.redisClient = null;
942
- }
943
- /** Reads prices from Pricer._loadPrices and uses a callback to set prices in redis */
944
- async startWithRedis(redisUrl) {
945
- await this.initRedis(redisUrl);
946
- logger.info(`Starting Pricer with Redis`);
947
- this._loadPrices(this._setRedisPrices.bind(this));
948
- setInterval(() => {
949
- this._loadPrices(this._setRedisPrices.bind(this));
950
- }, 3e4);
951
- }
952
- async close() {
953
- if (this.redisClient) {
954
- await this.redisClient.disconnect();
955
- }
956
- }
957
- async initRedis(redisUrl) {
958
- logger.info(`Initialising Redis Client`);
959
- this.redisClient = await (0, import_redis.createClient)({
820
+ // src/data/vesu-rebalance.abi.json
821
+ var vesu_rebalance_abi_default = [
822
+ {
823
+ type: "impl",
824
+ name: "ExternalImpl",
825
+ interface_name: "strkfarm_contracts::strategies::vesu_rebalance::interface::IVesuRebal"
826
+ },
827
+ {
828
+ type: "enum",
829
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::Feature",
830
+ variants: [
831
+ {
832
+ name: "DEPOSIT",
833
+ type: "()"
834
+ },
835
+ {
836
+ name: "WITHDRAW",
837
+ type: "()"
838
+ }
839
+ ]
840
+ },
841
+ {
842
+ type: "struct",
843
+ name: "core::integer::u256",
844
+ members: [
845
+ {
846
+ name: "low",
847
+ type: "core::integer::u128"
848
+ },
849
+ {
850
+ name: "high",
851
+ type: "core::integer::u128"
852
+ }
853
+ ]
854
+ },
855
+ {
856
+ type: "struct",
857
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::Action",
858
+ members: [
859
+ {
860
+ name: "pool_id",
861
+ type: "core::felt252"
862
+ },
863
+ {
864
+ name: "feature",
865
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Feature"
866
+ },
867
+ {
868
+ name: "token",
869
+ type: "core::starknet::contract_address::ContractAddress"
870
+ },
871
+ {
872
+ name: "amount",
873
+ type: "core::integer::u256"
874
+ }
875
+ ]
876
+ },
877
+ {
878
+ type: "struct",
879
+ name: "strkfarm_contracts::interfaces::IEkuboDistributor::Claim",
880
+ members: [
881
+ {
882
+ name: "id",
883
+ type: "core::integer::u64"
884
+ },
885
+ {
886
+ name: "claimee",
887
+ type: "core::starknet::contract_address::ContractAddress"
888
+ },
889
+ {
890
+ name: "amount",
891
+ type: "core::integer::u128"
892
+ }
893
+ ]
894
+ },
895
+ {
896
+ type: "struct",
897
+ name: "core::array::Span::<core::felt252>",
898
+ members: [
899
+ {
900
+ name: "snapshot",
901
+ type: "@core::array::Array::<core::felt252>"
902
+ }
903
+ ]
904
+ },
905
+ {
906
+ type: "struct",
907
+ name: "strkfarm_contracts::components::swap::Route",
908
+ members: [
909
+ {
910
+ name: "token_from",
911
+ type: "core::starknet::contract_address::ContractAddress"
912
+ },
913
+ {
914
+ name: "token_to",
915
+ type: "core::starknet::contract_address::ContractAddress"
916
+ },
917
+ {
918
+ name: "exchange_address",
919
+ type: "core::starknet::contract_address::ContractAddress"
920
+ },
921
+ {
922
+ name: "percent",
923
+ type: "core::integer::u128"
924
+ },
925
+ {
926
+ name: "additional_swap_params",
927
+ type: "core::array::Array::<core::felt252>"
928
+ }
929
+ ]
930
+ },
931
+ {
932
+ type: "struct",
933
+ name: "strkfarm_contracts::components::swap::AvnuMultiRouteSwap",
934
+ members: [
935
+ {
936
+ name: "token_from_address",
937
+ type: "core::starknet::contract_address::ContractAddress"
938
+ },
939
+ {
940
+ name: "token_from_amount",
941
+ type: "core::integer::u256"
942
+ },
943
+ {
944
+ name: "token_to_address",
945
+ type: "core::starknet::contract_address::ContractAddress"
946
+ },
947
+ {
948
+ name: "token_to_amount",
949
+ type: "core::integer::u256"
950
+ },
951
+ {
952
+ name: "token_to_min_amount",
953
+ type: "core::integer::u256"
954
+ },
955
+ {
956
+ name: "beneficiary",
957
+ type: "core::starknet::contract_address::ContractAddress"
958
+ },
959
+ {
960
+ name: "integrator_fee_amount_bps",
961
+ type: "core::integer::u128"
962
+ },
963
+ {
964
+ name: "integrator_fee_recipient",
965
+ type: "core::starknet::contract_address::ContractAddress"
966
+ },
967
+ {
968
+ name: "routes",
969
+ type: "core::array::Array::<strkfarm_contracts::components::swap::Route>"
970
+ }
971
+ ]
972
+ },
973
+ {
974
+ type: "struct",
975
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings",
976
+ members: [
977
+ {
978
+ name: "default_pool_index",
979
+ type: "core::integer::u8"
980
+ },
981
+ {
982
+ name: "fee_bps",
983
+ type: "core::integer::u32"
984
+ },
985
+ {
986
+ name: "fee_receiver",
987
+ type: "core::starknet::contract_address::ContractAddress"
988
+ }
989
+ ]
990
+ },
991
+ {
992
+ type: "struct",
993
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps",
994
+ members: [
995
+ {
996
+ name: "pool_id",
997
+ type: "core::felt252"
998
+ },
999
+ {
1000
+ name: "max_weight",
1001
+ type: "core::integer::u32"
1002
+ },
1003
+ {
1004
+ name: "v_token",
1005
+ type: "core::starknet::contract_address::ContractAddress"
1006
+ }
1007
+ ]
1008
+ },
1009
+ {
1010
+ type: "interface",
1011
+ name: "strkfarm_contracts::strategies::vesu_rebalance::interface::IVesuRebal",
1012
+ items: [
1013
+ {
1014
+ type: "function",
1015
+ name: "rebalance",
1016
+ inputs: [
1017
+ {
1018
+ name: "actions",
1019
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::Action>"
1020
+ }
1021
+ ],
1022
+ outputs: [],
1023
+ state_mutability: "external"
1024
+ },
1025
+ {
1026
+ type: "function",
1027
+ name: "rebalance_weights",
1028
+ inputs: [
1029
+ {
1030
+ name: "actions",
1031
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::Action>"
1032
+ }
1033
+ ],
1034
+ outputs: [],
1035
+ state_mutability: "external"
1036
+ },
1037
+ {
1038
+ type: "function",
1039
+ name: "emergency_withdraw",
1040
+ inputs: [],
1041
+ outputs: [],
1042
+ state_mutability: "external"
1043
+ },
1044
+ {
1045
+ type: "function",
1046
+ name: "emergency_withdraw_pool",
1047
+ inputs: [
1048
+ {
1049
+ name: "pool_index",
1050
+ type: "core::integer::u32"
1051
+ }
1052
+ ],
1053
+ outputs: [],
1054
+ state_mutability: "external"
1055
+ },
1056
+ {
1057
+ type: "function",
1058
+ name: "compute_yield",
1059
+ inputs: [],
1060
+ outputs: [
1061
+ {
1062
+ type: "(core::integer::u256, core::integer::u256)"
1063
+ }
1064
+ ],
1065
+ state_mutability: "view"
1066
+ },
1067
+ {
1068
+ type: "function",
1069
+ name: "harvest",
1070
+ inputs: [
1071
+ {
1072
+ name: "rewardsContract",
1073
+ type: "core::starknet::contract_address::ContractAddress"
1074
+ },
1075
+ {
1076
+ name: "claim",
1077
+ type: "strkfarm_contracts::interfaces::IEkuboDistributor::Claim"
1078
+ },
1079
+ {
1080
+ name: "proof",
1081
+ type: "core::array::Span::<core::felt252>"
1082
+ },
1083
+ {
1084
+ name: "swapInfo",
1085
+ type: "strkfarm_contracts::components::swap::AvnuMultiRouteSwap"
1086
+ }
1087
+ ],
1088
+ outputs: [],
1089
+ state_mutability: "external"
1090
+ },
1091
+ {
1092
+ type: "function",
1093
+ name: "set_settings",
1094
+ inputs: [
1095
+ {
1096
+ name: "settings",
1097
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings"
1098
+ }
1099
+ ],
1100
+ outputs: [],
1101
+ state_mutability: "external"
1102
+ },
1103
+ {
1104
+ type: "function",
1105
+ name: "set_allowed_pools",
1106
+ inputs: [
1107
+ {
1108
+ name: "pools",
1109
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps>"
1110
+ }
1111
+ ],
1112
+ outputs: [],
1113
+ state_mutability: "external"
1114
+ },
1115
+ {
1116
+ type: "function",
1117
+ name: "set_incentives_off",
1118
+ inputs: [],
1119
+ outputs: [],
1120
+ state_mutability: "external"
1121
+ },
1122
+ {
1123
+ type: "function",
1124
+ name: "get_settings",
1125
+ inputs: [],
1126
+ outputs: [
1127
+ {
1128
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings"
1129
+ }
1130
+ ],
1131
+ state_mutability: "view"
1132
+ },
1133
+ {
1134
+ type: "function",
1135
+ name: "get_allowed_pools",
1136
+ inputs: [],
1137
+ outputs: [
1138
+ {
1139
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps>"
1140
+ }
1141
+ ],
1142
+ state_mutability: "view"
1143
+ },
1144
+ {
1145
+ type: "function",
1146
+ name: "get_previous_index",
1147
+ inputs: [],
1148
+ outputs: [
1149
+ {
1150
+ type: "core::integer::u128"
1151
+ }
1152
+ ],
1153
+ state_mutability: "view"
1154
+ }
1155
+ ]
1156
+ },
1157
+ {
1158
+ type: "impl",
1159
+ name: "VesuERC4626Impl",
1160
+ interface_name: "strkfarm_contracts::interfaces::IERC4626::IERC4626"
1161
+ },
1162
+ {
1163
+ type: "interface",
1164
+ name: "strkfarm_contracts::interfaces::IERC4626::IERC4626",
1165
+ items: [
1166
+ {
1167
+ type: "function",
1168
+ name: "asset",
1169
+ inputs: [],
1170
+ outputs: [
1171
+ {
1172
+ type: "core::starknet::contract_address::ContractAddress"
1173
+ }
1174
+ ],
1175
+ state_mutability: "view"
1176
+ },
1177
+ {
1178
+ type: "function",
1179
+ name: "total_assets",
1180
+ inputs: [],
1181
+ outputs: [
1182
+ {
1183
+ type: "core::integer::u256"
1184
+ }
1185
+ ],
1186
+ state_mutability: "view"
1187
+ },
1188
+ {
1189
+ type: "function",
1190
+ name: "convert_to_shares",
1191
+ inputs: [
1192
+ {
1193
+ name: "assets",
1194
+ type: "core::integer::u256"
1195
+ }
1196
+ ],
1197
+ outputs: [
1198
+ {
1199
+ type: "core::integer::u256"
1200
+ }
1201
+ ],
1202
+ state_mutability: "view"
1203
+ },
1204
+ {
1205
+ type: "function",
1206
+ name: "convert_to_assets",
1207
+ inputs: [
1208
+ {
1209
+ name: "shares",
1210
+ type: "core::integer::u256"
1211
+ }
1212
+ ],
1213
+ outputs: [
1214
+ {
1215
+ type: "core::integer::u256"
1216
+ }
1217
+ ],
1218
+ state_mutability: "view"
1219
+ },
1220
+ {
1221
+ type: "function",
1222
+ name: "max_deposit",
1223
+ inputs: [
1224
+ {
1225
+ name: "receiver",
1226
+ type: "core::starknet::contract_address::ContractAddress"
1227
+ }
1228
+ ],
1229
+ outputs: [
1230
+ {
1231
+ type: "core::integer::u256"
1232
+ }
1233
+ ],
1234
+ state_mutability: "view"
1235
+ },
1236
+ {
1237
+ type: "function",
1238
+ name: "preview_deposit",
1239
+ inputs: [
1240
+ {
1241
+ name: "assets",
1242
+ type: "core::integer::u256"
1243
+ }
1244
+ ],
1245
+ outputs: [
1246
+ {
1247
+ type: "core::integer::u256"
1248
+ }
1249
+ ],
1250
+ state_mutability: "view"
1251
+ },
1252
+ {
1253
+ type: "function",
1254
+ name: "deposit",
1255
+ inputs: [
1256
+ {
1257
+ name: "assets",
1258
+ type: "core::integer::u256"
1259
+ },
1260
+ {
1261
+ name: "receiver",
1262
+ type: "core::starknet::contract_address::ContractAddress"
1263
+ }
1264
+ ],
1265
+ outputs: [
1266
+ {
1267
+ type: "core::integer::u256"
1268
+ }
1269
+ ],
1270
+ state_mutability: "external"
1271
+ },
1272
+ {
1273
+ type: "function",
1274
+ name: "max_mint",
1275
+ inputs: [
1276
+ {
1277
+ name: "receiver",
1278
+ type: "core::starknet::contract_address::ContractAddress"
1279
+ }
1280
+ ],
1281
+ outputs: [
1282
+ {
1283
+ type: "core::integer::u256"
1284
+ }
1285
+ ],
1286
+ state_mutability: "view"
1287
+ },
1288
+ {
1289
+ type: "function",
1290
+ name: "preview_mint",
1291
+ inputs: [
1292
+ {
1293
+ name: "shares",
1294
+ type: "core::integer::u256"
1295
+ }
1296
+ ],
1297
+ outputs: [
1298
+ {
1299
+ type: "core::integer::u256"
1300
+ }
1301
+ ],
1302
+ state_mutability: "view"
1303
+ },
1304
+ {
1305
+ type: "function",
1306
+ name: "mint",
1307
+ inputs: [
1308
+ {
1309
+ name: "shares",
1310
+ type: "core::integer::u256"
1311
+ },
1312
+ {
1313
+ name: "receiver",
1314
+ type: "core::starknet::contract_address::ContractAddress"
1315
+ }
1316
+ ],
1317
+ outputs: [
1318
+ {
1319
+ type: "core::integer::u256"
1320
+ }
1321
+ ],
1322
+ state_mutability: "external"
1323
+ },
1324
+ {
1325
+ type: "function",
1326
+ name: "max_withdraw",
1327
+ inputs: [
1328
+ {
1329
+ name: "owner",
1330
+ type: "core::starknet::contract_address::ContractAddress"
1331
+ }
1332
+ ],
1333
+ outputs: [
1334
+ {
1335
+ type: "core::integer::u256"
1336
+ }
1337
+ ],
1338
+ state_mutability: "view"
1339
+ },
1340
+ {
1341
+ type: "function",
1342
+ name: "preview_withdraw",
1343
+ inputs: [
1344
+ {
1345
+ name: "assets",
1346
+ type: "core::integer::u256"
1347
+ }
1348
+ ],
1349
+ outputs: [
1350
+ {
1351
+ type: "core::integer::u256"
1352
+ }
1353
+ ],
1354
+ state_mutability: "view"
1355
+ },
1356
+ {
1357
+ type: "function",
1358
+ name: "withdraw",
1359
+ inputs: [
1360
+ {
1361
+ name: "assets",
1362
+ type: "core::integer::u256"
1363
+ },
1364
+ {
1365
+ name: "receiver",
1366
+ type: "core::starknet::contract_address::ContractAddress"
1367
+ },
1368
+ {
1369
+ name: "owner",
1370
+ type: "core::starknet::contract_address::ContractAddress"
1371
+ }
1372
+ ],
1373
+ outputs: [
1374
+ {
1375
+ type: "core::integer::u256"
1376
+ }
1377
+ ],
1378
+ state_mutability: "external"
1379
+ },
1380
+ {
1381
+ type: "function",
1382
+ name: "max_redeem",
1383
+ inputs: [
1384
+ {
1385
+ name: "owner",
1386
+ type: "core::starknet::contract_address::ContractAddress"
1387
+ }
1388
+ ],
1389
+ outputs: [
1390
+ {
1391
+ type: "core::integer::u256"
1392
+ }
1393
+ ],
1394
+ state_mutability: "view"
1395
+ },
1396
+ {
1397
+ type: "function",
1398
+ name: "preview_redeem",
1399
+ inputs: [
1400
+ {
1401
+ name: "shares",
1402
+ type: "core::integer::u256"
1403
+ }
1404
+ ],
1405
+ outputs: [
1406
+ {
1407
+ type: "core::integer::u256"
1408
+ }
1409
+ ],
1410
+ state_mutability: "view"
1411
+ },
1412
+ {
1413
+ type: "function",
1414
+ name: "redeem",
1415
+ inputs: [
1416
+ {
1417
+ name: "shares",
1418
+ type: "core::integer::u256"
1419
+ },
1420
+ {
1421
+ name: "receiver",
1422
+ type: "core::starknet::contract_address::ContractAddress"
1423
+ },
1424
+ {
1425
+ name: "owner",
1426
+ type: "core::starknet::contract_address::ContractAddress"
1427
+ }
1428
+ ],
1429
+ outputs: [
1430
+ {
1431
+ type: "core::integer::u256"
1432
+ }
1433
+ ],
1434
+ state_mutability: "external"
1435
+ }
1436
+ ]
1437
+ },
1438
+ {
1439
+ type: "impl",
1440
+ name: "VesuERC20Impl",
1441
+ interface_name: "openzeppelin_token::erc20::interface::IERC20Mixin"
1442
+ },
1443
+ {
1444
+ type: "enum",
1445
+ name: "core::bool",
1446
+ variants: [
1447
+ {
1448
+ name: "False",
1449
+ type: "()"
1450
+ },
1451
+ {
1452
+ name: "True",
1453
+ type: "()"
1454
+ }
1455
+ ]
1456
+ },
1457
+ {
1458
+ type: "struct",
1459
+ name: "core::byte_array::ByteArray",
1460
+ members: [
1461
+ {
1462
+ name: "data",
1463
+ type: "core::array::Array::<core::bytes_31::bytes31>"
1464
+ },
1465
+ {
1466
+ name: "pending_word",
1467
+ type: "core::felt252"
1468
+ },
1469
+ {
1470
+ name: "pending_word_len",
1471
+ type: "core::integer::u32"
1472
+ }
1473
+ ]
1474
+ },
1475
+ {
1476
+ type: "interface",
1477
+ name: "openzeppelin_token::erc20::interface::IERC20Mixin",
1478
+ items: [
1479
+ {
1480
+ type: "function",
1481
+ name: "total_supply",
1482
+ inputs: [],
1483
+ outputs: [
1484
+ {
1485
+ type: "core::integer::u256"
1486
+ }
1487
+ ],
1488
+ state_mutability: "view"
1489
+ },
1490
+ {
1491
+ type: "function",
1492
+ name: "balance_of",
1493
+ inputs: [
1494
+ {
1495
+ name: "account",
1496
+ type: "core::starknet::contract_address::ContractAddress"
1497
+ }
1498
+ ],
1499
+ outputs: [
1500
+ {
1501
+ type: "core::integer::u256"
1502
+ }
1503
+ ],
1504
+ state_mutability: "view"
1505
+ },
1506
+ {
1507
+ type: "function",
1508
+ name: "allowance",
1509
+ inputs: [
1510
+ {
1511
+ name: "owner",
1512
+ type: "core::starknet::contract_address::ContractAddress"
1513
+ },
1514
+ {
1515
+ name: "spender",
1516
+ type: "core::starknet::contract_address::ContractAddress"
1517
+ }
1518
+ ],
1519
+ outputs: [
1520
+ {
1521
+ type: "core::integer::u256"
1522
+ }
1523
+ ],
1524
+ state_mutability: "view"
1525
+ },
1526
+ {
1527
+ type: "function",
1528
+ name: "transfer",
1529
+ inputs: [
1530
+ {
1531
+ name: "recipient",
1532
+ type: "core::starknet::contract_address::ContractAddress"
1533
+ },
1534
+ {
1535
+ name: "amount",
1536
+ type: "core::integer::u256"
1537
+ }
1538
+ ],
1539
+ outputs: [
1540
+ {
1541
+ type: "core::bool"
1542
+ }
1543
+ ],
1544
+ state_mutability: "external"
1545
+ },
1546
+ {
1547
+ type: "function",
1548
+ name: "transfer_from",
1549
+ inputs: [
1550
+ {
1551
+ name: "sender",
1552
+ type: "core::starknet::contract_address::ContractAddress"
1553
+ },
1554
+ {
1555
+ name: "recipient",
1556
+ type: "core::starknet::contract_address::ContractAddress"
1557
+ },
1558
+ {
1559
+ name: "amount",
1560
+ type: "core::integer::u256"
1561
+ }
1562
+ ],
1563
+ outputs: [
1564
+ {
1565
+ type: "core::bool"
1566
+ }
1567
+ ],
1568
+ state_mutability: "external"
1569
+ },
1570
+ {
1571
+ type: "function",
1572
+ name: "approve",
1573
+ inputs: [
1574
+ {
1575
+ name: "spender",
1576
+ type: "core::starknet::contract_address::ContractAddress"
1577
+ },
1578
+ {
1579
+ name: "amount",
1580
+ type: "core::integer::u256"
1581
+ }
1582
+ ],
1583
+ outputs: [
1584
+ {
1585
+ type: "core::bool"
1586
+ }
1587
+ ],
1588
+ state_mutability: "external"
1589
+ },
1590
+ {
1591
+ type: "function",
1592
+ name: "name",
1593
+ inputs: [],
1594
+ outputs: [
1595
+ {
1596
+ type: "core::byte_array::ByteArray"
1597
+ }
1598
+ ],
1599
+ state_mutability: "view"
1600
+ },
1601
+ {
1602
+ type: "function",
1603
+ name: "symbol",
1604
+ inputs: [],
1605
+ outputs: [
1606
+ {
1607
+ type: "core::byte_array::ByteArray"
1608
+ }
1609
+ ],
1610
+ state_mutability: "view"
1611
+ },
1612
+ {
1613
+ type: "function",
1614
+ name: "decimals",
1615
+ inputs: [],
1616
+ outputs: [
1617
+ {
1618
+ type: "core::integer::u8"
1619
+ }
1620
+ ],
1621
+ state_mutability: "view"
1622
+ },
1623
+ {
1624
+ type: "function",
1625
+ name: "totalSupply",
1626
+ inputs: [],
1627
+ outputs: [
1628
+ {
1629
+ type: "core::integer::u256"
1630
+ }
1631
+ ],
1632
+ state_mutability: "view"
1633
+ },
1634
+ {
1635
+ type: "function",
1636
+ name: "balanceOf",
1637
+ inputs: [
1638
+ {
1639
+ name: "account",
1640
+ type: "core::starknet::contract_address::ContractAddress"
1641
+ }
1642
+ ],
1643
+ outputs: [
1644
+ {
1645
+ type: "core::integer::u256"
1646
+ }
1647
+ ],
1648
+ state_mutability: "view"
1649
+ },
1650
+ {
1651
+ type: "function",
1652
+ name: "transferFrom",
1653
+ inputs: [
1654
+ {
1655
+ name: "sender",
1656
+ type: "core::starknet::contract_address::ContractAddress"
1657
+ },
1658
+ {
1659
+ name: "recipient",
1660
+ type: "core::starknet::contract_address::ContractAddress"
1661
+ },
1662
+ {
1663
+ name: "amount",
1664
+ type: "core::integer::u256"
1665
+ }
1666
+ ],
1667
+ outputs: [
1668
+ {
1669
+ type: "core::bool"
1670
+ }
1671
+ ],
1672
+ state_mutability: "external"
1673
+ }
1674
+ ]
1675
+ },
1676
+ {
1677
+ type: "impl",
1678
+ name: "CommonCompImpl",
1679
+ interface_name: "strkfarm_contracts::interfaces::common::ICommon"
1680
+ },
1681
+ {
1682
+ type: "interface",
1683
+ name: "strkfarm_contracts::interfaces::common::ICommon",
1684
+ items: [
1685
+ {
1686
+ type: "function",
1687
+ name: "upgrade",
1688
+ inputs: [
1689
+ {
1690
+ name: "new_class",
1691
+ type: "core::starknet::class_hash::ClassHash"
1692
+ }
1693
+ ],
1694
+ outputs: [],
1695
+ state_mutability: "external"
1696
+ },
1697
+ {
1698
+ type: "function",
1699
+ name: "pause",
1700
+ inputs: [],
1701
+ outputs: [],
1702
+ state_mutability: "external"
1703
+ },
1704
+ {
1705
+ type: "function",
1706
+ name: "unpause",
1707
+ inputs: [],
1708
+ outputs: [],
1709
+ state_mutability: "external"
1710
+ },
1711
+ {
1712
+ type: "function",
1713
+ name: "is_paused",
1714
+ inputs: [],
1715
+ outputs: [
1716
+ {
1717
+ type: "core::bool"
1718
+ }
1719
+ ],
1720
+ state_mutability: "view"
1721
+ }
1722
+ ]
1723
+ },
1724
+ {
1725
+ type: "impl",
1726
+ name: "RewardShareImpl",
1727
+ interface_name: "strkfarm_contracts::components::harvester::reward_shares::IRewardShare"
1728
+ },
1729
+ {
1730
+ type: "struct",
1731
+ name: "strkfarm_contracts::components::harvester::reward_shares::UserRewardsInfo",
1732
+ members: [
1733
+ {
1734
+ name: "pending_round_points",
1735
+ type: "core::integer::u128"
1736
+ },
1737
+ {
1738
+ name: "shares_owned",
1739
+ type: "core::integer::u128"
1740
+ },
1741
+ {
1742
+ name: "block_number",
1743
+ type: "core::integer::u64"
1744
+ },
1745
+ {
1746
+ name: "index",
1747
+ type: "core::integer::u32"
1748
+ }
1749
+ ]
1750
+ },
1751
+ {
1752
+ type: "struct",
1753
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardsInfo",
1754
+ members: [
1755
+ {
1756
+ name: "amount",
1757
+ type: "core::integer::u128"
1758
+ },
1759
+ {
1760
+ name: "shares",
1761
+ type: "core::integer::u128"
1762
+ },
1763
+ {
1764
+ name: "total_round_points",
1765
+ type: "core::integer::u128"
1766
+ },
1767
+ {
1768
+ name: "block_number",
1769
+ type: "core::integer::u64"
1770
+ }
1771
+ ]
1772
+ },
1773
+ {
1774
+ type: "interface",
1775
+ name: "strkfarm_contracts::components::harvester::reward_shares::IRewardShare",
1776
+ items: [
1777
+ {
1778
+ type: "function",
1779
+ name: "get_user_reward_info",
1780
+ inputs: [
1781
+ {
1782
+ name: "user",
1783
+ type: "core::starknet::contract_address::ContractAddress"
1784
+ }
1785
+ ],
1786
+ outputs: [
1787
+ {
1788
+ type: "strkfarm_contracts::components::harvester::reward_shares::UserRewardsInfo"
1789
+ }
1790
+ ],
1791
+ state_mutability: "view"
1792
+ },
1793
+ {
1794
+ type: "function",
1795
+ name: "get_rewards_info",
1796
+ inputs: [
1797
+ {
1798
+ name: "index",
1799
+ type: "core::integer::u32"
1800
+ }
1801
+ ],
1802
+ outputs: [
1803
+ {
1804
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardsInfo"
1805
+ }
1806
+ ],
1807
+ state_mutability: "view"
1808
+ },
1809
+ {
1810
+ type: "function",
1811
+ name: "get_total_rewards",
1812
+ inputs: [],
1813
+ outputs: [
1814
+ {
1815
+ type: "core::integer::u32"
1816
+ }
1817
+ ],
1818
+ state_mutability: "view"
1819
+ },
1820
+ {
1821
+ type: "function",
1822
+ name: "get_total_unminted_shares",
1823
+ inputs: [],
1824
+ outputs: [
1825
+ {
1826
+ type: "core::integer::u128"
1827
+ }
1828
+ ],
1829
+ state_mutability: "view"
1830
+ },
1831
+ {
1832
+ type: "function",
1833
+ name: "get_additional_shares",
1834
+ inputs: [
1835
+ {
1836
+ name: "user",
1837
+ type: "core::starknet::contract_address::ContractAddress"
1838
+ }
1839
+ ],
1840
+ outputs: [
1841
+ {
1842
+ type: "(core::integer::u128, core::integer::u64, core::integer::u128)"
1843
+ }
1844
+ ],
1845
+ state_mutability: "view"
1846
+ }
1847
+ ]
1848
+ },
1849
+ {
1850
+ type: "struct",
1851
+ name: "strkfarm_contracts::interfaces::IVesu::IStonDispatcher",
1852
+ members: [
1853
+ {
1854
+ name: "contract_address",
1855
+ type: "core::starknet::contract_address::ContractAddress"
1856
+ }
1857
+ ]
1858
+ },
1859
+ {
1860
+ type: "struct",
1861
+ name: "strkfarm_contracts::components::vesu::vesuStruct",
1862
+ members: [
1863
+ {
1864
+ name: "singleton",
1865
+ type: "strkfarm_contracts::interfaces::IVesu::IStonDispatcher"
1866
+ },
1867
+ {
1868
+ name: "pool_id",
1869
+ type: "core::felt252"
1870
+ },
1871
+ {
1872
+ name: "debt",
1873
+ type: "core::starknet::contract_address::ContractAddress"
1874
+ },
1875
+ {
1876
+ name: "col",
1877
+ type: "core::starknet::contract_address::ContractAddress"
1878
+ },
1879
+ {
1880
+ name: "oracle",
1881
+ type: "core::starknet::contract_address::ContractAddress"
1882
+ }
1883
+ ]
1884
+ },
1885
+ {
1886
+ type: "constructor",
1887
+ name: "constructor",
1888
+ inputs: [
1889
+ {
1890
+ name: "asset",
1891
+ type: "core::starknet::contract_address::ContractAddress"
1892
+ },
1893
+ {
1894
+ name: "access_control",
1895
+ type: "core::starknet::contract_address::ContractAddress"
1896
+ },
1897
+ {
1898
+ name: "allowed_pools",
1899
+ type: "core::array::Array::<strkfarm_contracts::strategies::vesu_rebalance::interface::PoolProps>"
1900
+ },
1901
+ {
1902
+ name: "settings",
1903
+ type: "strkfarm_contracts::strategies::vesu_rebalance::interface::Settings"
1904
+ },
1905
+ {
1906
+ name: "vesu_settings",
1907
+ type: "strkfarm_contracts::components::vesu::vesuStruct"
1908
+ }
1909
+ ]
1910
+ },
1911
+ {
1912
+ type: "event",
1913
+ name: "openzeppelin_security::reentrancyguard::ReentrancyGuardComponent::Event",
1914
+ kind: "enum",
1915
+ variants: []
1916
+ },
1917
+ {
1918
+ type: "event",
1919
+ name: "strkfarm_contracts::components::erc4626::ERC4626Component::Deposit",
1920
+ kind: "struct",
1921
+ members: [
1922
+ {
1923
+ name: "sender",
1924
+ type: "core::starknet::contract_address::ContractAddress",
1925
+ kind: "key"
1926
+ },
1927
+ {
1928
+ name: "owner",
1929
+ type: "core::starknet::contract_address::ContractAddress",
1930
+ kind: "key"
1931
+ },
1932
+ {
1933
+ name: "assets",
1934
+ type: "core::integer::u256",
1935
+ kind: "data"
1936
+ },
1937
+ {
1938
+ name: "shares",
1939
+ type: "core::integer::u256",
1940
+ kind: "data"
1941
+ }
1942
+ ]
1943
+ },
1944
+ {
1945
+ type: "event",
1946
+ name: "strkfarm_contracts::components::erc4626::ERC4626Component::Withdraw",
1947
+ kind: "struct",
1948
+ members: [
1949
+ {
1950
+ name: "sender",
1951
+ type: "core::starknet::contract_address::ContractAddress",
1952
+ kind: "key"
1953
+ },
1954
+ {
1955
+ name: "receiver",
1956
+ type: "core::starknet::contract_address::ContractAddress",
1957
+ kind: "key"
1958
+ },
1959
+ {
1960
+ name: "owner",
1961
+ type: "core::starknet::contract_address::ContractAddress",
1962
+ kind: "key"
1963
+ },
1964
+ {
1965
+ name: "assets",
1966
+ type: "core::integer::u256",
1967
+ kind: "data"
1968
+ },
1969
+ {
1970
+ name: "shares",
1971
+ type: "core::integer::u256",
1972
+ kind: "data"
1973
+ }
1974
+ ]
1975
+ },
1976
+ {
1977
+ type: "event",
1978
+ name: "strkfarm_contracts::components::erc4626::ERC4626Component::Event",
1979
+ kind: "enum",
1980
+ variants: [
1981
+ {
1982
+ name: "Deposit",
1983
+ type: "strkfarm_contracts::components::erc4626::ERC4626Component::Deposit",
1984
+ kind: "nested"
1985
+ },
1986
+ {
1987
+ name: "Withdraw",
1988
+ type: "strkfarm_contracts::components::erc4626::ERC4626Component::Withdraw",
1989
+ kind: "nested"
1990
+ }
1991
+ ]
1992
+ },
1993
+ {
1994
+ type: "event",
1995
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Rewards",
1996
+ kind: "struct",
1997
+ members: [
1998
+ {
1999
+ name: "index",
2000
+ type: "core::integer::u32",
2001
+ kind: "data"
2002
+ },
2003
+ {
2004
+ name: "info",
2005
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardsInfo",
2006
+ kind: "data"
2007
+ },
2008
+ {
2009
+ name: "total_reward_shares",
2010
+ type: "core::integer::u128",
2011
+ kind: "data"
2012
+ },
2013
+ {
2014
+ name: "timestamp",
2015
+ type: "core::integer::u64",
2016
+ kind: "data"
2017
+ }
2018
+ ]
2019
+ },
2020
+ {
2021
+ type: "event",
2022
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::UserRewards",
2023
+ kind: "struct",
2024
+ members: [
2025
+ {
2026
+ name: "user",
2027
+ type: "core::starknet::contract_address::ContractAddress",
2028
+ kind: "key"
2029
+ },
2030
+ {
2031
+ name: "info",
2032
+ type: "strkfarm_contracts::components::harvester::reward_shares::UserRewardsInfo",
2033
+ kind: "data"
2034
+ },
2035
+ {
2036
+ name: "total_reward_shares",
2037
+ type: "core::integer::u128",
2038
+ kind: "data"
2039
+ },
2040
+ {
2041
+ name: "timestamp",
2042
+ type: "core::integer::u64",
2043
+ kind: "data"
2044
+ }
2045
+ ]
2046
+ },
2047
+ {
2048
+ type: "event",
2049
+ name: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Event",
2050
+ kind: "enum",
2051
+ variants: [
2052
+ {
2053
+ name: "Rewards",
2054
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Rewards",
2055
+ kind: "nested"
2056
+ },
2057
+ {
2058
+ name: "UserRewards",
2059
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::UserRewards",
2060
+ kind: "nested"
2061
+ }
2062
+ ]
2063
+ },
2064
+ {
2065
+ type: "event",
2066
+ name: "openzeppelin_token::erc20::erc20::ERC20Component::Transfer",
2067
+ kind: "struct",
2068
+ members: [
2069
+ {
2070
+ name: "from",
2071
+ type: "core::starknet::contract_address::ContractAddress",
2072
+ kind: "key"
2073
+ },
2074
+ {
2075
+ name: "to",
2076
+ type: "core::starknet::contract_address::ContractAddress",
2077
+ kind: "key"
2078
+ },
2079
+ {
2080
+ name: "value",
2081
+ type: "core::integer::u256",
2082
+ kind: "data"
2083
+ }
2084
+ ]
2085
+ },
2086
+ {
2087
+ type: "event",
2088
+ name: "openzeppelin_token::erc20::erc20::ERC20Component::Approval",
2089
+ kind: "struct",
2090
+ members: [
2091
+ {
2092
+ name: "owner",
2093
+ type: "core::starknet::contract_address::ContractAddress",
2094
+ kind: "key"
2095
+ },
2096
+ {
2097
+ name: "spender",
2098
+ type: "core::starknet::contract_address::ContractAddress",
2099
+ kind: "key"
2100
+ },
2101
+ {
2102
+ name: "value",
2103
+ type: "core::integer::u256",
2104
+ kind: "data"
2105
+ }
2106
+ ]
2107
+ },
2108
+ {
2109
+ type: "event",
2110
+ name: "openzeppelin_token::erc20::erc20::ERC20Component::Event",
2111
+ kind: "enum",
2112
+ variants: [
2113
+ {
2114
+ name: "Transfer",
2115
+ type: "openzeppelin_token::erc20::erc20::ERC20Component::Transfer",
2116
+ kind: "nested"
2117
+ },
2118
+ {
2119
+ name: "Approval",
2120
+ type: "openzeppelin_token::erc20::erc20::ERC20Component::Approval",
2121
+ kind: "nested"
2122
+ }
2123
+ ]
2124
+ },
2125
+ {
2126
+ type: "event",
2127
+ name: "openzeppelin_introspection::src5::SRC5Component::Event",
2128
+ kind: "enum",
2129
+ variants: []
2130
+ },
2131
+ {
2132
+ type: "event",
2133
+ name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
2134
+ kind: "struct",
2135
+ members: [
2136
+ {
2137
+ name: "class_hash",
2138
+ type: "core::starknet::class_hash::ClassHash",
2139
+ kind: "data"
2140
+ }
2141
+ ]
2142
+ },
2143
+ {
2144
+ type: "event",
2145
+ name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
2146
+ kind: "enum",
2147
+ variants: [
2148
+ {
2149
+ name: "Upgraded",
2150
+ type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
2151
+ kind: "nested"
2152
+ }
2153
+ ]
2154
+ },
2155
+ {
2156
+ type: "event",
2157
+ name: "openzeppelin_security::pausable::PausableComponent::Paused",
2158
+ kind: "struct",
2159
+ members: [
2160
+ {
2161
+ name: "account",
2162
+ type: "core::starknet::contract_address::ContractAddress",
2163
+ kind: "data"
2164
+ }
2165
+ ]
2166
+ },
2167
+ {
2168
+ type: "event",
2169
+ name: "openzeppelin_security::pausable::PausableComponent::Unpaused",
2170
+ kind: "struct",
2171
+ members: [
2172
+ {
2173
+ name: "account",
2174
+ type: "core::starknet::contract_address::ContractAddress",
2175
+ kind: "data"
2176
+ }
2177
+ ]
2178
+ },
2179
+ {
2180
+ type: "event",
2181
+ name: "openzeppelin_security::pausable::PausableComponent::Event",
2182
+ kind: "enum",
2183
+ variants: [
2184
+ {
2185
+ name: "Paused",
2186
+ type: "openzeppelin_security::pausable::PausableComponent::Paused",
2187
+ kind: "nested"
2188
+ },
2189
+ {
2190
+ name: "Unpaused",
2191
+ type: "openzeppelin_security::pausable::PausableComponent::Unpaused",
2192
+ kind: "nested"
2193
+ }
2194
+ ]
2195
+ },
2196
+ {
2197
+ type: "event",
2198
+ name: "strkfarm_contracts::components::common::CommonComp::Event",
2199
+ kind: "enum",
2200
+ variants: []
2201
+ },
2202
+ {
2203
+ type: "event",
2204
+ name: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::Rebalance",
2205
+ kind: "struct",
2206
+ members: [
2207
+ {
2208
+ name: "yield_before",
2209
+ type: "core::integer::u128",
2210
+ kind: "data"
2211
+ },
2212
+ {
2213
+ name: "yield_after",
2214
+ type: "core::integer::u128",
2215
+ kind: "data"
2216
+ }
2217
+ ]
2218
+ },
2219
+ {
2220
+ type: "event",
2221
+ name: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::CollectFees",
2222
+ kind: "struct",
2223
+ members: [
2224
+ {
2225
+ name: "fee_collected",
2226
+ type: "core::integer::u128",
2227
+ kind: "data"
2228
+ },
2229
+ {
2230
+ name: "fee_collector",
2231
+ type: "core::starknet::contract_address::ContractAddress",
2232
+ kind: "data"
2233
+ }
2234
+ ]
2235
+ },
2236
+ {
2237
+ type: "event",
2238
+ name: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::Event",
2239
+ kind: "enum",
2240
+ variants: [
2241
+ {
2242
+ name: "ReentrancyGuardEvent",
2243
+ type: "openzeppelin_security::reentrancyguard::ReentrancyGuardComponent::Event",
2244
+ kind: "flat"
2245
+ },
2246
+ {
2247
+ name: "ERC4626Event",
2248
+ type: "strkfarm_contracts::components::erc4626::ERC4626Component::Event",
2249
+ kind: "flat"
2250
+ },
2251
+ {
2252
+ name: "RewardShareEvent",
2253
+ type: "strkfarm_contracts::components::harvester::reward_shares::RewardShareComponent::Event",
2254
+ kind: "flat"
2255
+ },
2256
+ {
2257
+ name: "ERC20Event",
2258
+ type: "openzeppelin_token::erc20::erc20::ERC20Component::Event",
2259
+ kind: "flat"
2260
+ },
2261
+ {
2262
+ name: "SRC5Event",
2263
+ type: "openzeppelin_introspection::src5::SRC5Component::Event",
2264
+ kind: "flat"
2265
+ },
2266
+ {
2267
+ name: "UpgradeableEvent",
2268
+ type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
2269
+ kind: "flat"
2270
+ },
2271
+ {
2272
+ name: "PausableEvent",
2273
+ type: "openzeppelin_security::pausable::PausableComponent::Event",
2274
+ kind: "flat"
2275
+ },
2276
+ {
2277
+ name: "CommonCompEvent",
2278
+ type: "strkfarm_contracts::components::common::CommonComp::Event",
2279
+ kind: "flat"
2280
+ },
2281
+ {
2282
+ name: "Rebalance",
2283
+ type: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::Rebalance",
2284
+ kind: "nested"
2285
+ },
2286
+ {
2287
+ name: "CollectFees",
2288
+ type: "strkfarm_contracts::strategies::vesu_rebalance::vesu_rebalance::VesuRebalance::CollectFees",
2289
+ kind: "nested"
2290
+ }
2291
+ ]
2292
+ }
2293
+ ];
2294
+
2295
+ // src/utils/index.ts
2296
+ function assert(condition, message) {
2297
+ if (!condition) {
2298
+ throw new Error(message);
2299
+ }
2300
+ }
2301
+
2302
+ // src/strategies/vesu-rebalance.ts
2303
+ var import_axios5 = __toESM(require("axios"));
2304
+ var VesuRebalance = class _VesuRebalance {
2305
+ // 10000 bps = 100%
2306
+ /**
2307
+ * Creates a new VesuRebalance strategy instance.
2308
+ * @param config - Configuration object containing provider and other settings
2309
+ * @param pricer - Pricer instance for token price calculations
2310
+ * @param metadata - Strategy metadata including deposit tokens and address
2311
+ * @throws {Error} If more than one deposit token is specified
2312
+ */
2313
+ constructor(config, pricer, metadata) {
2314
+ this.BASE_WEIGHT = 1e4;
2315
+ this.config = config;
2316
+ this.pricer = pricer;
2317
+ assert(metadata.depositTokens.length === 1, "VesuRebalance only supports 1 deposit token");
2318
+ this.metadata = metadata;
2319
+ this.address = metadata.address;
2320
+ this.contract = new import_starknet5.Contract(vesu_rebalance_abi_default, this.address.address, this.config.provider);
2321
+ }
2322
+ /**
2323
+ * Creates a deposit call to the strategy contract.
2324
+ * @param assets - Amount of assets to deposit
2325
+ * @param receiver - Address that will receive the strategy tokens
2326
+ * @returns Populated contract call for deposit
2327
+ */
2328
+ depositCall(assets, receiver) {
2329
+ const assetContract = new import_starknet5.Contract(vesu_rebalance_abi_default, this.metadata.depositTokens[0].address, this.config.provider);
2330
+ const call1 = assetContract.populate("approve", [this.address.address, import_starknet5.uint256.bnToUint256(assets.toWei())]);
2331
+ const call2 = this.contract.populate("deposit", [import_starknet5.uint256.bnToUint256(assets.toWei()), receiver.address]);
2332
+ return [call1, call2];
2333
+ }
2334
+ /**
2335
+ * Creates a withdrawal call to the strategy contract.
2336
+ * @param assets - Amount of assets to withdraw
2337
+ * @param receiver - Address that will receive the withdrawn assets
2338
+ * @param owner - Address that owns the strategy tokens
2339
+ * @returns Populated contract call for withdrawal
2340
+ */
2341
+ withdrawCall(assets, receiver, owner) {
2342
+ return [this.contract.populate("withdraw", [import_starknet5.uint256.bnToUint256(assets.toWei()), receiver.address, owner.address])];
2343
+ }
2344
+ /**
2345
+ * Returns the underlying asset token of the strategy.
2346
+ * @returns The deposit token supported by this strategy
2347
+ */
2348
+ asset() {
2349
+ return this.metadata.depositTokens[0];
2350
+ }
2351
+ /**
2352
+ * Returns the number of decimals used by the strategy token.
2353
+ * @returns Number of decimals (same as the underlying token)
2354
+ */
2355
+ decimals() {
2356
+ return this.metadata.depositTokens[0].decimals;
2357
+ }
2358
+ /**
2359
+ * Calculates the Total Value Locked (TVL) for a specific user.
2360
+ * @param user - Address of the user
2361
+ * @returns Object containing the amount in token units and USD value
2362
+ */
2363
+ async getUserTVL(user) {
2364
+ const shares = await this.contract.balanceOf(user.address);
2365
+ const assets = await this.contract.convert_to_assets(import_starknet5.uint256.bnToUint256(shares));
2366
+ const amount = Web3Number.fromWei(assets.toString(), this.metadata.depositTokens[0].decimals);
2367
+ let price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
2368
+ const usdValue = Number(amount.toFixed(6)) * price.price;
2369
+ return {
2370
+ amount,
2371
+ usdValue
2372
+ };
2373
+ }
2374
+ /**
2375
+ * Calculates the total TVL of the strategy.
2376
+ * @returns Object containing the total amount in token units and USD value
2377
+ */
2378
+ async getTVL() {
2379
+ const assets = await this.contract.total_assets();
2380
+ const amount = Web3Number.fromWei(assets.toString(), this.metadata.depositTokens[0].decimals);
2381
+ let price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
2382
+ const usdValue = Number(amount.toFixed(6)) * price.price;
2383
+ return {
2384
+ amount,
2385
+ usdValue
2386
+ };
2387
+ }
2388
+ /**
2389
+ * Retrieves the list of allowed pools and their detailed information from multiple sources:
2390
+ * 1. Contract's allowed pools
2391
+ * 2. Vesu positions API for current positions
2392
+ * 3. Vesu pools API for APY and utilization data
2393
+ *
2394
+ * @returns {Promise<{
2395
+ * data: Array<PoolInfoFull>,
2396
+ * isErrorPositionsAPI: boolean
2397
+ * }>} Object containing:
2398
+ * - data: Array of pool information including IDs, weights, amounts, APYs and utilization
2399
+ * - isErrorPositionsAPI: Boolean indicating if there was an error fetching position data
2400
+ */
2401
+ async getPools() {
2402
+ const allowedPools = (await this.contract.get_allowed_pools()).map((p) => ({
2403
+ pool_id: ContractAddr.from(p.pool_id),
2404
+ max_weight: Number(p.max_weight) / this.BASE_WEIGHT,
2405
+ v_token: ContractAddr.from(p.v_token)
2406
+ }));
2407
+ let isErrorPositionsAPI = false;
2408
+ let vesuPositions = [];
2409
+ try {
2410
+ const res = await import_axios5.default.get(`https://api.vesu.xyz/positions?walletAddress=${this.address.address}`);
2411
+ const data2 = await res.data;
2412
+ vesuPositions = data2.data;
2413
+ } catch (e) {
2414
+ console.error(`${_VesuRebalance.name}: Error fetching pools for ${this.address.address}`, e);
2415
+ isErrorPositionsAPI = true;
2416
+ }
2417
+ let isErrorPoolsAPI = false;
2418
+ let pools = [];
2419
+ try {
2420
+ const res = await import_axios5.default.get(`https://api.vesu.xyz/pools`);
2421
+ const data2 = await res.data;
2422
+ pools = data2.data;
2423
+ } catch (e) {
2424
+ console.error(`${_VesuRebalance.name}: Error fetching pools for ${this.address.address}`, e);
2425
+ isErrorPoolsAPI = true;
2426
+ }
2427
+ const totalAssets = (await this.getTVL()).amount;
2428
+ const info = allowedPools.map(async (p) => {
2429
+ const vesuPosition = vesuPositions.find((d) => d.pool.id.toString() === import_starknet5.num.getDecimalString(p.pool_id.address.toString()));
2430
+ const pool = pools.find((d) => d.id == import_starknet5.num.getDecimalString(p.pool_id.address));
2431
+ const assetInfo = pool?.assets.find((d) => ContractAddr.from(this.asset().address).eqString(d.address));
2432
+ let vTokenContract = new import_starknet5.Contract(vesu_rebalance_abi_default, p.v_token.address, this.config.provider);
2433
+ const bal = await vTokenContract.balanceOf(this.address.address);
2434
+ const assets = await vTokenContract.convert_to_assets(import_starknet5.uint256.bnToUint256(bal.toString()));
2435
+ const item = {
2436
+ pool_id: p.pool_id,
2437
+ pool_name: vesuPosition?.pool.name,
2438
+ max_weight: p.max_weight,
2439
+ current_weight: isErrorPositionsAPI || !vesuPosition ? 0 : Number(Web3Number.fromWei(vesuPosition.collateral.value, this.decimals()).dividedBy(totalAssets.toString()).toFixed(6)),
2440
+ v_token: p.v_token,
2441
+ amount: Web3Number.fromWei(assets.toString(), this.decimals()),
2442
+ usdValue: isErrorPositionsAPI || !vesuPosition ? Web3Number.fromWei("0", this.decimals()) : Web3Number.fromWei(vesuPosition.collateral.usdPrice.value, vesuPosition.collateral.usdPrice.decimals),
2443
+ APY: isErrorPoolsAPI || !assetInfo ? {
2444
+ baseApy: 0,
2445
+ defiSpringApy: 0,
2446
+ netApy: 0
2447
+ } : {
2448
+ baseApy: Number(Web3Number.fromWei(assetInfo.stats.supplyApy.value, assetInfo.stats.supplyApy.decimals).toFixed(6)),
2449
+ defiSpringApy: Number(Web3Number.fromWei(assetInfo.stats.defiSpringSupplyApr.value, assetInfo.stats.defiSpringSupplyApr.decimals).toFixed(6)),
2450
+ netApy: 0
2451
+ },
2452
+ currentUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(Web3Number.fromWei(assetInfo.stats.currentUtilization.value, assetInfo.stats.currentUtilization.decimals).toFixed(6)),
2453
+ maxUtilization: isErrorPoolsAPI || !assetInfo ? 0 : Number(Web3Number.fromWei(assetInfo.config.maxUtilization.value, assetInfo.config.maxUtilization.decimals).toFixed(6))
2454
+ };
2455
+ item.APY.netApy = item.APY.baseApy + item.APY.defiSpringApy;
2456
+ return item;
2457
+ });
2458
+ const data = await Promise.all(info);
2459
+ return {
2460
+ data,
2461
+ isErrorPositionsAPI,
2462
+ isErrorPoolsAPI,
2463
+ isError: isErrorPositionsAPI || isErrorPoolsAPI
2464
+ };
2465
+ }
2466
+ /**
2467
+ * Calculates the weighted average APY across all pools based on USD value.
2468
+ * @returns {Promise<number>} The weighted average APY across all pools
2469
+ */
2470
+ async netAPY() {
2471
+ const { data: pools } = await this.getPools();
2472
+ return this.netAPYGivenPools(pools);
2473
+ }
2474
+ /**
2475
+ * Calculates the weighted average APY across all pools based on USD value.
2476
+ * @returns {Promise<number>} The weighted average APY across all pools
2477
+ */
2478
+ netAPYGivenPools(pools) {
2479
+ const weightedApy = pools.reduce((acc, curr) => {
2480
+ const weight = curr.current_weight;
2481
+ return acc + curr.APY.netApy * weight;
2482
+ }, 0);
2483
+ return weightedApy;
2484
+ }
2485
+ /**
2486
+ * Calculates optimal position changes to maximize APY while respecting max weights.
2487
+ * The algorithm:
2488
+ * 1. Sorts pools by APY (highest first)
2489
+ * 2. Calculates target amounts based on max weights
2490
+ * 3. For each pool that needs more funds:
2491
+ * - Takes funds from lowest APY pools that are over their target
2492
+ * 4. Validates that total assets remain constant
2493
+ *
2494
+ * @returns {Promise<{
2495
+ * changes: Change[],
2496
+ * finalPools: PoolInfoFull[],
2497
+ * isAnyPoolOverMaxWeight: boolean
2498
+ * }>} Object containing:
2499
+ * - changes: Array of position changes
2500
+ * - finalPools: Array of pool information after rebalance
2501
+ * @throws Error if rebalance is not possible while maintaining constraints
2502
+ */
2503
+ async getRebalancedPositions() {
2504
+ const { data: pools } = await this.getPools();
2505
+ const totalAssets = (await this.getTVL()).amount;
2506
+ if (totalAssets.eq(0)) return {
2507
+ changes: [],
2508
+ finalPools: []
2509
+ };
2510
+ const sumPools = pools.reduce((acc, curr) => acc.plus(curr.amount.toString()), Web3Number.fromWei("0", this.decimals()));
2511
+ assert(sumPools.lte(totalAssets), "Sum of pools.amount must be less than or equal to totalAssets");
2512
+ const sortedPools = [...pools].sort((a, b) => b.APY.netApy - a.APY.netApy);
2513
+ const targetAmounts = {};
2514
+ let remainingAssets = totalAssets;
2515
+ let isAnyPoolOverMaxWeight = false;
2516
+ for (const pool of sortedPools) {
2517
+ const maxAmount = totalAssets.multipliedBy(pool.max_weight * 0.9);
2518
+ const targetAmount = remainingAssets.gte(maxAmount) ? maxAmount : remainingAssets;
2519
+ targetAmounts[pool.pool_id.address.toString()] = targetAmount;
2520
+ remainingAssets = remainingAssets.minus(targetAmount.toString());
2521
+ if (pool.current_weight > pool.max_weight) {
2522
+ isAnyPoolOverMaxWeight = true;
2523
+ }
2524
+ }
2525
+ assert(remainingAssets.lt(1e-5), "Remaining assets must be 0");
2526
+ const changes = sortedPools.map((pool) => {
2527
+ const target = targetAmounts[pool.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
2528
+ const change = Web3Number.fromWei(target.minus(pool.amount.toString()).toWei(), this.decimals());
2529
+ return {
2530
+ pool_id: pool.pool_id,
2531
+ changeAmt: change,
2532
+ finalAmt: target,
2533
+ isDeposit: change.gt(0)
2534
+ };
2535
+ });
2536
+ const sumChanges = changes.reduce((sum, c) => sum.plus(c.changeAmt.toString()), Web3Number.fromWei("0", this.decimals()));
2537
+ const sumFinal = changes.reduce((sum, c) => sum.plus(c.finalAmt.toString()), Web3Number.fromWei("0", this.decimals()));
2538
+ const hasChanges = changes.some((c) => !c.changeAmt.eq(0));
2539
+ if (!sumChanges.eq(0)) throw new Error("Sum of changes must be zero");
2540
+ if (!sumFinal.eq(totalAssets)) throw new Error("Sum of final amounts must equal total assets");
2541
+ if (!hasChanges) throw new Error("No changes required");
2542
+ const finalPools = pools.map((p) => {
2543
+ const target = targetAmounts[p.pool_id.address.toString()] || Web3Number.fromWei("0", this.decimals());
2544
+ return {
2545
+ ...p,
2546
+ amount: target,
2547
+ usdValue: Web3Number.fromWei("0", this.decimals())
2548
+ };
2549
+ });
2550
+ return {
2551
+ changes,
2552
+ finalPools,
2553
+ isAnyPoolOverMaxWeight
2554
+ };
2555
+ }
2556
+ /**
2557
+ * Creates a rebalance Call object for the strategy contract
2558
+ * @param pools - Array of pool information including IDs, weights, amounts, APYs and utilization
2559
+ * @returns Populated contract call for rebalance
2560
+ */
2561
+ async getRebalanceCall(pools, isOverWeightAdjustment) {
2562
+ const actions = [];
2563
+ pools.sort((a, b) => b.isDeposit ? -1 : 1);
2564
+ console.log("pools", pools);
2565
+ pools.forEach((p) => {
2566
+ if (p.changeAmt.eq(0)) return null;
2567
+ actions.push({
2568
+ pool_id: p.pool_id.address,
2569
+ feature: new import_starknet5.CairoCustomEnum(p.isDeposit ? { DEPOSIT: {} } : { WITHDRAW: {} }),
2570
+ token: this.asset().address,
2571
+ amount: import_starknet5.uint256.bnToUint256(p.changeAmt.multipliedBy(p.isDeposit ? 1 : -1).toWei())
2572
+ });
2573
+ });
2574
+ if (actions.length === 0) return null;
2575
+ if (isOverWeightAdjustment) {
2576
+ return this.contract.populate("rebalance_weights", [actions]);
2577
+ }
2578
+ return this.contract.populate("rebalance", [actions]);
2579
+ }
2580
+ async getInvestmentFlows(pools) {
2581
+ const netYield = this.netAPYGivenPools(pools);
2582
+ const baseFlow = {
2583
+ title: "Deposit $1000",
2584
+ subItems: [`Net yield: ${(netYield * 100).toFixed(2)}%`],
2585
+ linkedFlows: []
2586
+ };
2587
+ pools.forEach((p) => {
2588
+ if (p.amount.eq(0)) return;
2589
+ const flow = {
2590
+ title: `${p.pool_name} - $${(p.current_weight * 1e3).toFixed(2)}`,
2591
+ subItems: [
2592
+ `APY: ${(p.APY.netApy * 100).toFixed(2)}%`,
2593
+ `Weight: ${(p.current_weight * 100).toFixed(2)}% / ${(p.max_weight * 100).toFixed(2)}%`
2594
+ ],
2595
+ linkedFlows: []
2596
+ };
2597
+ baseFlow.linkedFlows.push(flow);
2598
+ });
2599
+ return [baseFlow];
2600
+ }
2601
+ };
2602
+ 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.";
2603
+ var _protocol = { name: "Vesu", logo: "https://static-assets-8zct.onrender.com/integrations/vesu/logo.png" };
2604
+ var _riskFactor = [
2605
+ { type: "SMART_CONTRACT_RISK" /* SMART_CONTRACT_RISK */, value: 0.5, weight: 25 },
2606
+ { type: "TECHNICAL_RISK" /* TECHNICAL_RISK */, value: 0.5, weight: 25 },
2607
+ { type: "COUNTERPARTY_RISK" /* COUNTERPARTY_RISK */, value: 1, weight: 50 }
2608
+ ];
2609
+ var VesuRebalanceStrategies = [{
2610
+ name: "Vesu STRK",
2611
+ description: _description.replace("{{TOKEN}}", "STRK"),
2612
+ address: ContractAddr.from("0xeeb729d554ae486387147b13a9c8871bc7991d454e8b5ff570d4bf94de71e1"),
2613
+ type: "ERC4626",
2614
+ depositTokens: [Global.getDefaultTokens().find((t) => t.symbol === "STRK")],
2615
+ protocols: [_protocol],
2616
+ maxTVL: Web3Number.fromWei("0", 18),
2617
+ risk: {
2618
+ riskFactor: _riskFactor,
2619
+ netRisk: _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / 100
2620
+ }
2621
+ }];
2622
+
2623
+ // src/notifs/telegram.ts
2624
+ var import_node_telegram_bot_api = __toESM(require("node-telegram-bot-api"));
2625
+ var TelegramNotif = class {
2626
+ constructor(token, shouldPoll) {
2627
+ this.subscribers = [
2628
+ // '6820228303',
2629
+ "1505578076",
2630
+ // '5434736198', // maaza
2631
+ "1356705582",
2632
+ // langs
2633
+ "1388729514",
2634
+ // hwashere
2635
+ "6020162572",
2636
+ //minato
2637
+ "985902592"
2638
+ ];
2639
+ this.bot = new import_node_telegram_bot_api.default(token, { polling: shouldPoll });
2640
+ }
2641
+ // listen to start msgs, register chatId and send registered msg
2642
+ activateChatBot() {
2643
+ this.bot.on("message", (msg) => {
2644
+ const chatId = msg.chat.id;
2645
+ let text = msg.text.toLowerCase().trim();
2646
+ logger.verbose(`Tg: IncomingMsg: ID: ${chatId}, msg: ${text}`);
2647
+ if (text == "start") {
2648
+ this.bot.sendMessage(chatId, "Registered");
2649
+ this.subscribers.push(chatId);
2650
+ logger.verbose(`Tg: New subscriber: ${chatId}`);
2651
+ } else {
2652
+ this.bot.sendMessage(chatId, "Unrecognized command. Supported commands: start");
2653
+ }
2654
+ });
2655
+ }
2656
+ // send a given msg to all registered users
2657
+ sendMessage(msg) {
2658
+ logger.verbose(`Tg: Sending message: ${msg}`);
2659
+ for (let chatId of this.subscribers) {
2660
+ this.bot.sendMessage(chatId, msg).catch((err) => {
2661
+ logger.error(`Tg: Error sending msg to ${chatId}`);
2662
+ logger.error(`Tg: Error sending message: ${err.message}`);
2663
+ }).then(() => {
2664
+ logger.verbose(`Tg: Message sent to ${chatId}`);
2665
+ });
2666
+ }
2667
+ }
2668
+ };
2669
+
2670
+ // src/node/pricer-redis.ts
2671
+ var import_redis = require("redis");
2672
+ var PricerRedis = class extends Pricer {
2673
+ constructor(config, tokens2) {
2674
+ super(config, tokens2);
2675
+ this.redisClient = null;
2676
+ }
2677
+ /** Reads prices from Pricer._loadPrices and uses a callback to set prices in redis */
2678
+ async startWithRedis(redisUrl) {
2679
+ await this.initRedis(redisUrl);
2680
+ logger.info(`Starting Pricer with Redis`);
2681
+ this._loadPrices(this._setRedisPrices.bind(this));
2682
+ setInterval(() => {
2683
+ this._loadPrices(this._setRedisPrices.bind(this));
2684
+ }, 3e4);
2685
+ }
2686
+ async close() {
2687
+ if (this.redisClient) {
2688
+ await this.redisClient.disconnect();
2689
+ }
2690
+ }
2691
+ async initRedis(redisUrl) {
2692
+ logger.info(`Initialising Redis Client`);
2693
+ this.redisClient = await (0, import_redis.createClient)({
960
2694
  url: redisUrl
961
2695
  });
962
2696
  this.redisClient.on("error", (err) => console.log("Redis Client Error", err)).connect();
@@ -989,6 +2723,164 @@ var PricerRedis = class extends Pricer {
989
2723
  return priceInfo;
990
2724
  }
991
2725
  };
2726
+
2727
+ // src/utils/store.ts
2728
+ var import_fs = __toESM(require("fs"));
2729
+ var import_starknet6 = require("starknet");
2730
+ var crypto2 = __toESM(require("crypto"));
2731
+
2732
+ // src/utils/encrypt.ts
2733
+ var crypto = __toESM(require("crypto"));
2734
+ var PasswordJsonCryptoUtil = class {
2735
+ constructor() {
2736
+ this.algorithm = "aes-256-gcm";
2737
+ this.keyLength = 32;
2738
+ // 256 bits
2739
+ this.saltLength = 16;
2740
+ // 128 bits
2741
+ this.ivLength = 12;
2742
+ // 96 bits for GCM
2743
+ this.tagLength = 16;
2744
+ // 128 bits
2745
+ this.pbkdf2Iterations = 1e5;
2746
+ }
2747
+ // Number of iterations for PBKDF2
2748
+ deriveKey(password, salt) {
2749
+ return crypto.pbkdf2Sync(password, salt, this.pbkdf2Iterations, this.keyLength, "sha256");
2750
+ }
2751
+ encrypt(data, password) {
2752
+ const jsonString = JSON.stringify(data);
2753
+ const salt = crypto.randomBytes(this.saltLength);
2754
+ const iv = crypto.randomBytes(this.ivLength);
2755
+ const key = this.deriveKey(password, salt);
2756
+ const cipher = crypto.createCipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
2757
+ let encrypted = cipher.update(jsonString, "utf8", "hex");
2758
+ encrypted += cipher.final("hex");
2759
+ const tag = cipher.getAuthTag();
2760
+ return Buffer.concat([salt, iv, tag, Buffer.from(encrypted, "hex")]).toString("base64");
2761
+ }
2762
+ decrypt(encryptedData, password) {
2763
+ const data = Buffer.from(encryptedData, "base64");
2764
+ const salt = data.subarray(0, this.saltLength);
2765
+ const iv = data.subarray(this.saltLength, this.saltLength + this.ivLength);
2766
+ const tag = data.subarray(this.saltLength + this.ivLength, this.saltLength + this.ivLength + this.tagLength);
2767
+ const encrypted = data.subarray(this.saltLength + this.ivLength + this.tagLength);
2768
+ const key = this.deriveKey(password, salt);
2769
+ const decipher = crypto.createDecipheriv(this.algorithm, key, iv, { authTagLength: this.tagLength });
2770
+ decipher.setAuthTag(tag);
2771
+ try {
2772
+ let decrypted = decipher.update(encrypted.toString("hex"), "hex", "utf8");
2773
+ decrypted += decipher.final("utf8");
2774
+ return JSON.parse(decrypted);
2775
+ } catch (error) {
2776
+ throw new Error("Decryption failed. This could be due to an incorrect password or corrupted data.");
2777
+ }
2778
+ }
2779
+ };
2780
+
2781
+ // src/utils/store.ts
2782
+ function getDefaultStoreConfig(network) {
2783
+ if (!process.env.HOME) {
2784
+ throw new Error("StoreConfig: HOME environment variable not found");
2785
+ }
2786
+ return {
2787
+ SECRET_FILE_FOLDER: `${process.env.HOME}/.starknet-store`,
2788
+ NETWORK: network,
2789
+ ACCOUNTS_FILE_NAME: "accounts.json",
2790
+ PASSWORD: crypto2.randomBytes(16).toString("hex")
2791
+ };
2792
+ }
2793
+ var Store = class _Store {
2794
+ constructor(config, storeConfig) {
2795
+ this.encryptor = new PasswordJsonCryptoUtil();
2796
+ this.config = config;
2797
+ const defaultStoreConfig = getDefaultStoreConfig(config.network);
2798
+ if (!storeConfig.PASSWORD) {
2799
+ _Store.logPassword(defaultStoreConfig.PASSWORD);
2800
+ }
2801
+ this.storeConfig = {
2802
+ ...defaultStoreConfig,
2803
+ ...storeConfig
2804
+ };
2805
+ _Store.ensureFolder(this.storeConfig.SECRET_FILE_FOLDER);
2806
+ }
2807
+ static logPassword(password) {
2808
+ logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
2809
+ logger.warn(`Generated a random password for store`);
2810
+ logger.warn(`\u26A0\uFE0F Password: ${password}`);
2811
+ logger.warn(`This not stored anywhere, please you backup this password for future use`);
2812
+ logger.warn(`\u26A0\uFE0F=========================================\u26A0\uFE0F`);
2813
+ }
2814
+ getAccount(accountKey, txVersion = import_starknet6.constants.TRANSACTION_VERSION.V2) {
2815
+ const accounts = this.loadAccounts();
2816
+ logger.verbose(`nAccounts loaded for network: ${Object.keys(accounts).length}`);
2817
+ const data = accounts[accountKey];
2818
+ if (!data) {
2819
+ throw new Error(`Account not found: ${accountKey}`);
2820
+ }
2821
+ logger.verbose(`Account loaded: ${accountKey} from network: ${this.config.network}`);
2822
+ logger.verbose(`Address: ${data.address}`);
2823
+ const acc = new import_starknet6.Account(this.config.provider, data.address, data.pk, void 0, txVersion);
2824
+ return acc;
2825
+ }
2826
+ addAccount(accountKey, address, pk) {
2827
+ const allAccounts = this.getAllAccounts();
2828
+ if (!allAccounts[this.config.network]) {
2829
+ allAccounts[this.config.network] = {};
2830
+ }
2831
+ allAccounts[this.config.network][accountKey] = {
2832
+ address,
2833
+ pk
2834
+ };
2835
+ const encryptedData = this.encryptor.encrypt(allAccounts, this.storeConfig.PASSWORD);
2836
+ (0, import_fs.writeFileSync)(this.getAccountFilePath(), encryptedData);
2837
+ logger.verbose(`Account added: ${accountKey} to network: ${this.config.network}`);
2838
+ }
2839
+ getAccountFilePath() {
2840
+ const path = `${this.storeConfig.SECRET_FILE_FOLDER}/${this.storeConfig.ACCOUNTS_FILE_NAME}`;
2841
+ logger.verbose(`Path: ${path}`);
2842
+ return path;
2843
+ }
2844
+ getAllAccounts() {
2845
+ const PATH = this.getAccountFilePath();
2846
+ if (!import_fs.default.existsSync(PATH)) {
2847
+ logger.verbose(`Accounts: files doesnt exist`);
2848
+ return {};
2849
+ }
2850
+ let encryptedData = (0, import_fs.readFileSync)(PATH, {
2851
+ encoding: "utf-8"
2852
+ });
2853
+ let data = this.encryptor.decrypt(encryptedData, this.storeConfig.PASSWORD);
2854
+ return data;
2855
+ }
2856
+ /**
2857
+ * @description Load all accounts of the network
2858
+ * @returns NetworkAccounts
2859
+ */
2860
+ loadAccounts() {
2861
+ const allData = this.getAllAccounts();
2862
+ logger.verbose(`Accounts loaded for network: ${this.config.network}`);
2863
+ if (!allData[this.config.network]) {
2864
+ allData[this.config.network] = {};
2865
+ }
2866
+ return allData[this.config.network];
2867
+ }
2868
+ /**
2869
+ * @description List all accountKeys of the network
2870
+ * @returns string[]
2871
+ */
2872
+ listAccounts() {
2873
+ return Object.keys(this.loadAccounts());
2874
+ }
2875
+ static ensureFolder(folder) {
2876
+ if (!import_fs.default.existsSync(folder)) {
2877
+ import_fs.default.mkdirSync(folder, { recursive: true });
2878
+ }
2879
+ if (!import_fs.default.existsSync(`${folder}`)) {
2880
+ throw new Error(`Store folder not found: ${folder}`);
2881
+ }
2882
+ }
2883
+ };
992
2884
  // Annotate the CommonJS export names for ESM import in node:
993
2885
  0 && (module.exports = {
994
2886
  AutoCompounderSTRK,
@@ -1002,11 +2894,16 @@ var PricerRedis = class extends Pricer {
1002
2894
  PasswordJsonCryptoUtil,
1003
2895
  Pragma,
1004
2896
  Pricer,
2897
+ PricerFromApi,
1005
2898
  PricerRedis,
2899
+ RiskType,
1006
2900
  Store,
1007
2901
  TelegramNotif,
2902
+ VesuRebalance,
2903
+ VesuRebalanceStrategies,
1008
2904
  Web3Number,
1009
2905
  ZkLend,
2906
+ assert,
1010
2907
  getDefaultStoreConfig,
1011
2908
  getMainnetConfig,
1012
2909
  logger