@strkfarm/sdk 1.0.57 → 1.0.59

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.0.57",
3
+ "version": "1.0.59",
4
4
  "description": "STRKFarm TS SDK (Meant for our internal use, but feel free to use it)",
5
5
  "typings": "dist/index.d.ts",
6
6
  "types": "dist/index.d.ts",
@@ -54,11 +54,12 @@
54
54
  "@types/react": "^19.1.2",
55
55
  "axios": "^1.7.2",
56
56
  "react": "19.1.0",
57
- "starknet": "^6.11.0"
57
+ "starknet": "7.6.4"
58
58
  },
59
59
  "dependencies": {
60
60
  "@avnu/avnu-sdk": "3.0.2",
61
61
  "@ericnordelo/strk-merkle-tree": "^1.0.0",
62
+ "@scure/starknet": "^2.0.0",
62
63
  "bignumber.js": "4.0.4",
63
64
  "browser-assert": "^1.2.1",
64
65
  "chalk": "^4.1.2",
@@ -1,5 +1,5 @@
1
1
  import { ContractAddr, Web3Number } from "@/dataTypes";
2
- import { BlockIdentifier, RpcProvider } from "starknet";
2
+ import { BlockIdentifier, constants, RpcProvider } from "starknet";
3
3
  import React, { ReactNode } from "react";
4
4
 
5
5
  export enum RiskType {
@@ -107,12 +107,14 @@ export interface IInvestmentFlow {
107
107
 
108
108
  export function getMainnetConfig(
109
109
  rpcUrl: string = 'https://starknet-mainnet.public.blastapi.io',
110
- blockIdentifier: BlockIdentifier = "pending"
110
+ blockIdentifier: BlockIdentifier = "pending",
111
+ // specVersion = constants.SupportedRpcVersion.v0_8_1
111
112
  ): IConfig {
112
113
  return {
113
114
  provider: new RpcProvider({
114
115
  nodeUrl: rpcUrl,
115
- blockIdentifier: blockIdentifier
116
+ blockIdentifier: blockIdentifier,
117
+ // specVersion
116
118
  }),
117
119
  stage: "production",
118
120
  network: Network.mainnet
@@ -36,7 +36,7 @@ function getAccount(
36
36
  PASSWORD: password
37
37
  });
38
38
 
39
- return store.getAccount(accountKey);
39
+ return store.getAccount(accountKey, '0x3');
40
40
  }
41
41
 
42
42
  async function myDeclare(contract_name: string, package_name: string = 'strkfarm', config: IConfig, acc: Account) {
@@ -96,7 +96,7 @@ async function deployContract(contract_name: string, classHash: string, construc
96
96
  classHash,
97
97
  constructorCalldata: constructorData,
98
98
  })
99
- console.log("Deploy fee", contract_name, Number(fee.suggestedMaxFee) / 10 ** 18, 'ETH')
99
+ console.log("Deploy fee", contract_name, Number(fee.overall_fee) / 10 ** 18, 'ETH')
100
100
 
101
101
  const tx = await acc.deployContract({
102
102
  classHash,
@@ -9,17 +9,23 @@ import UniversalVaultAbi from '../data/universal-vault.abi.json';
9
9
  import ManagerAbi from '../data/vault-manager.abi.json';
10
10
  import { ApproveCallParams, BaseAdapter, CommonAdapter, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall, VesuAdapter, VesuModifyPositionCallParams, VesuPools } from "./universal-adapters";
11
11
  import { Global } from "@/global";
12
+ import { ERC20 } from "@/modules";
12
13
 
13
14
  export interface UniversalStrategySettings {
14
15
  manager: ContractAddr,
15
16
  vaultAllocator: ContractAddr,
16
17
  redeemRequestNFT: ContractAddr,
18
+ aumOracle: ContractAddr,
17
19
  leafAdapters: LeafAdapterFn<any>[],
18
20
  adapters: {id: string, adapter: BaseAdapter}[],
19
21
  targetHealthFactor: number,
20
22
  minHealthFactor: number
21
23
  }
22
24
 
25
+ export enum AUMTypes {
26
+ FINALISED = 'finalised',
27
+ DEFISPRING = 'defispring'
28
+ }
23
29
 
24
30
  export class UniversalStrategy<
25
31
  S extends UniversalStrategySettings
@@ -139,6 +145,20 @@ export class UniversalStrategy<
139
145
  return [call1, call2];
140
146
  }
141
147
 
148
+ async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
149
+ assert(
150
+ amountInfo.tokenInfo.address.eq(this.asset().address),
151
+ "Withdraw token mismatch"
152
+ );
153
+ const shares = await this.contract.call('convert_to_shares', [uint256.bnToUint256(amountInfo.amount.toWei())]);
154
+ const call = this.contract.populate("request_redeem", [
155
+ uint256.bnToUint256(shares.toString()),
156
+ receiver.address,
157
+ owner.address
158
+ ]);
159
+ return [call];
160
+ }
161
+
142
162
  /**
143
163
  * Calculates the Total Value Locked (TVL) for a specific user.
144
164
  * @param user - Address of the user
@@ -190,14 +210,22 @@ export class UniversalStrategy<
190
210
  const debt2APY = Number(debtAsset2.borrowApr.value) / 1e18;
191
211
 
192
212
  const positions = await this.getVaultPositions();
213
+ logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
214
+ if (positions.every(p => p.amount.isZero())) {
215
+ return { net: 0, splits: [{
216
+ apy: 0, id: 'base'
217
+ }, {
218
+ apy: 0, id: 'defispring'
219
+ }]};
220
+ }
193
221
  const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
194
222
  const baseAPYs = [collateral1APY, debt1APY, collateral2APY, debt2APY];
195
223
  assert(positions.length == baseAPYs.length, "Positions and APYs length mismatch");
196
224
  const rewardAPYs = [Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18, 0, Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18, 0];
197
225
  const baseAPY = this.computeAPY(baseAPYs, weights);
198
226
  const rewardAPY = this.computeAPY(rewardAPYs, weights);
199
- const apys = [...baseAPYs, ...rewardAPYs];
200
227
  const netAPY = baseAPY + rewardAPY;
228
+ logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
201
229
  return { net: netAPY, splits: [{
202
230
  apy: baseAPY, id: 'base'
203
231
  }, {
@@ -233,6 +261,17 @@ export class UniversalStrategy<
233
261
  };
234
262
  }
235
263
 
264
+ async getUnusedBalance(): Promise<SingleTokenInfo> {
265
+ const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
266
+ const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
267
+ const usdValue = Number(balance.toFixed(6)) * price.price;
268
+ return {
269
+ tokenInfo: this.asset(),
270
+ amount: balance,
271
+ usdValue
272
+ };
273
+ }
274
+
236
275
  async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
237
276
  const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
238
277
  const lastReportTime = await this.contract.call('last_report_timestamp', []);
@@ -244,10 +283,29 @@ export class UniversalStrategy<
244
283
  const leg1AUM = await vesuAdapter1.getPositions(this.config);
245
284
  const leg2AUM = await vesuAdapter2.getPositions(this.config);
246
285
 
247
- const aumToken = leg1AUM[0].amount
286
+ const balance = await this.getUnusedBalance();
287
+ logger.verbose(`${this.getTag()} unused balance: ${balance.amount.toNumber()}`);
288
+
289
+ const vesuAum = leg1AUM[0].amount
248
290
  .plus(leg2AUM[0].usdValue / token1Price.price)
249
291
  .minus(leg1AUM[1].usdValue / token1Price.price)
250
292
  .minus(leg2AUM[1].amount);
293
+
294
+ const zeroAmt = Web3Number.fromWei('0', this.asset().decimals);
295
+ const net = {
296
+ tokenInfo: this.asset(),
297
+ amount: zeroAmt,
298
+ usdValue: 0
299
+ };
300
+ const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
301
+ if (vesuAum.isZero()) {
302
+ return { net, splits: [{
303
+ aum: zeroAmt, id: AUMTypes.FINALISED
304
+ }, {
305
+ aum: zeroAmt, id: AUMTypes.DEFISPRING
306
+ }], prevAum};
307
+ }
308
+ const aumToken = vesuAum.plus(balance.amount);
251
309
  logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
252
310
 
253
311
  // calculate estimated growth from strk rewards
@@ -257,7 +315,6 @@ export class UniversalStrategy<
257
315
 
258
316
  const timeDiff = (Math.round(Date.now() / 1000) - Number(lastReportTime));
259
317
  const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
260
- const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
261
318
  const rewardAssets = prevAum.multipliedBy(growthRate);
262
319
  logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
263
320
  logger.verbose(`${this.getTag()} Current AUM: ${currentAUM}`);
@@ -267,16 +324,13 @@ export class UniversalStrategy<
267
324
  const newAUM = aumToken.plus(rewardAssets);
268
325
  logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
269
326
 
270
- const net = {
271
- tokenInfo: this.asset(),
272
- amount: newAUM,
273
- usdValue: newAUM.multipliedBy(token1Price.price).toNumber()
274
- };
327
+ net.amount = newAUM;
328
+ net.usdValue = newAUM.multipliedBy(token1Price.price).toNumber();
275
329
  const splits = [{
276
- id: 'finalised',
330
+ id: AUMTypes.FINALISED,
277
331
  aum: aumToken
278
332
  }, {
279
- id: 'defispring',
333
+ id: AUMTypes.DEFISPRING,
280
334
  aum: rewardAssets
281
335
  }];
282
336
  return { net, splits, prevAum };
@@ -632,6 +686,7 @@ const usdcVaultSettings: UniversalStrategySettings = {
632
686
  manager: ContractAddr.from('0xf41a2b1f498a7f9629db0b8519259e66e964260a23d20003f3e42bb1997a07'),
633
687
  vaultAllocator: ContractAddr.from('0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba'),
634
688
  redeemRequestNFT: ContractAddr.from('0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda'),
689
+ aumOracle: ContractAddr.from("0x6faf45ed185dec13ef723c9ead4266cab98d06f2cb237e331b1fa5c2aa79afe"),
635
690
  leafAdapters: [],
636
691
  adapters: [],
637
692
  targetHealthFactor: 1.3,
@@ -642,6 +697,40 @@ const wbtcVaultSettings: UniversalStrategySettings = {
642
697
  manager: ContractAddr.from('0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34'),
643
698
  vaultAllocator: ContractAddr.from('0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735'),
644
699
  redeemRequestNFT: ContractAddr.from('0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2'),
700
+ aumOracle: ContractAddr.from("0x2edf4edbed3f839e7f07dcd913e92299898ff4cf0ba532f8c572c66c5b331b2"),
701
+ leafAdapters: [],
702
+ adapters: [],
703
+ targetHealthFactor: 1.3,
704
+ minHealthFactor: 1.25
705
+ }
706
+
707
+ const ethVaultSettings: UniversalStrategySettings = {
708
+ manager: ContractAddr.from('0x494888b37206616bd09d759dcda61e5118470b9aa7f58fb84f21c778a7b8f97'),
709
+ vaultAllocator: ContractAddr.from('0x4acc0ad6bea58cb578d60ff7c31f06f44369a7a9a7bbfffe4701f143e427bd'),
710
+ redeemRequestNFT: ContractAddr.from('0x2e6cd71e5060a254d4db00655e420db7bf89da7755bb0d5f922e2f00c76ac49'),
711
+ aumOracle: ContractAddr.from("0x4b747f2e75c057bed9aa2ce46fbdc2159dc684c15bd32d4f95983a6ecf39a05"),
712
+ leafAdapters: [],
713
+ adapters: [],
714
+ targetHealthFactor: 1.3,
715
+ minHealthFactor: 1.25
716
+ }
717
+
718
+ const strkVaultSettings: UniversalStrategySettings = {
719
+ manager: ContractAddr.from('0xcc6a5153ca56293405506eb20826a379d982cd738008ef7e808454d318fb81'),
720
+ vaultAllocator: ContractAddr.from('0xf29d2f82e896c0ed74c9eff220af34ac148e8b99846d1ace9fbb02c9191d01'),
721
+ redeemRequestNFT: ContractAddr.from('0x46902423bd632c428376b84fcee9cac5dbe016214e93a8103bcbde6e1de656b'),
722
+ aumOracle: ContractAddr.from("0x6d7dbfad4bb51715da211468389a623da00c0625f8f6efbea822ee5ac5231f4"),
723
+ leafAdapters: [],
724
+ adapters: [],
725
+ targetHealthFactor: 1.3,
726
+ minHealthFactor: 1.25
727
+ }
728
+
729
+ const usdtVaultSettings: UniversalStrategySettings = {
730
+ manager: ContractAddr.from('0x39bb9843503799b552b7ed84b31c06e4ff10c0537edcddfbf01fe944b864029'),
731
+ vaultAllocator: ContractAddr.from('0x56437d18c43727ac971f6c7086031cad7d9d6ccb340f4f3785a74cc791c931a'),
732
+ redeemRequestNFT: ContractAddr.from('0x5af0c2a657eaa8e23ed78e855dac0c51e4f69e2cf91a18c472041a1f75bb41f'),
733
+ aumOracle: ContractAddr.from("0x7018f8040c8066a4ab929e6760ae52dd43b6a3a289172f514750a61fcc565cc"),
645
734
  leafAdapters: [],
646
735
  adapters: [],
647
736
  targetHealthFactor: 1.3,
@@ -692,4 +781,67 @@ export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[]
692
781
  faqs: [],
693
782
  investmentSteps: [],
694
783
  },
784
+ {
785
+ name: "ETH Evergreen",
786
+ description: "A universal strategy for managing ETH assets",
787
+ address: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
788
+ launchBlock: 0,
789
+ type: 'ERC4626',
790
+ depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'ETH')!],
791
+ additionalInfo: getLooperSettings('ETH', 'WBTC', ethVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
792
+ risk: {
793
+ riskFactor: _riskFactor,
794
+ netRisk:
795
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
796
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
797
+ notARisks: getNoRiskTags(_riskFactor)
798
+ },
799
+ protocols: [Protocols.VESU],
800
+ maxTVL: Web3Number.fromWei(0, 18),
801
+ contractDetails: [],
802
+ faqs: [],
803
+ investmentSteps: [],
804
+ },
805
+ {
806
+ name: "STRK Evergreen",
807
+ description: "A universal strategy for managing STRK assets",
808
+ address: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
809
+ launchBlock: 0,
810
+ type: 'ERC4626',
811
+ depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'STRK')!],
812
+ additionalInfo: getLooperSettings('STRK', 'ETH', strkVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
813
+ risk: {
814
+ riskFactor: _riskFactor,
815
+ netRisk:
816
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
817
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
818
+ notARisks: getNoRiskTags(_riskFactor)
819
+ },
820
+ protocols: [Protocols.VESU],
821
+ maxTVL: Web3Number.fromWei(0, 18),
822
+ contractDetails: [],
823
+ faqs: [],
824
+ investmentSteps: [],
825
+ },
826
+ {
827
+ name: "USDT Evergreen",
828
+ description: "A universal strategy for managing USDT assets",
829
+ address: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
830
+ launchBlock: 0,
831
+ type: 'ERC4626',
832
+ depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDT')!],
833
+ additionalInfo: getLooperSettings('USDT', 'ETH', usdtVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
834
+ risk: {
835
+ riskFactor: _riskFactor,
836
+ netRisk:
837
+ _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
838
+ _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
839
+ notARisks: getNoRiskTags(_riskFactor)
840
+ },
841
+ protocols: [Protocols.VESU],
842
+ maxTVL: Web3Number.fromWei(0, 6),
843
+ contractDetails: [],
844
+ faqs: [],
845
+ investmentSteps: [],
846
+ }
695
847
  ]
@@ -1,29 +1,29 @@
1
- interface CacheData {
2
- timestamp: number;
3
- ttl: number;
4
- data: any;
5
- }
6
- export class CacheClass {
7
- readonly cache: Map<string, CacheData> = new Map();
8
-
9
- setCache(key: string, data: any, ttl: number = 60000): void {
10
- const timestamp = Date.now();
11
- this.cache.set(key, { timestamp, ttl, data });
12
- }
13
-
14
- getCache<T>(key: string): T | null {
15
- const cachedData = this.cache.get(key);
16
- if (!cachedData || !this.isCacheValid(key)) {
17
- return null;
18
- }
19
- return cachedData.data;
20
- }
21
-
22
- isCacheValid(key: string): boolean {
23
- const cachedData = this.cache.get(key);
24
- if (!cachedData) return false;
25
-
26
- const { timestamp, ttl } = cachedData;
27
- return Date.now() - timestamp <= ttl;
28
- }
1
+ interface CacheData {
2
+ timestamp: number;
3
+ ttl: number;
4
+ data: any;
5
+ }
6
+ export class CacheClass {
7
+ readonly cache: Map<string, CacheData> = new Map();
8
+
9
+ setCache(key: string, data: any, ttl: number = 60000): void {
10
+ const timestamp = Date.now();
11
+ this.cache.set(key, { timestamp, ttl, data });
12
+ }
13
+
14
+ getCache<T>(key: string): T | null {
15
+ const cachedData = this.cache.get(key);
16
+ if (!cachedData || !this.isCacheValid(key)) {
17
+ return null;
18
+ }
19
+ return cachedData.data;
20
+ }
21
+
22
+ isCacheValid(key: string): boolean {
23
+ const cachedData = this.cache.get(key);
24
+ if (!cachedData) return false;
25
+
26
+ const { timestamp, ttl } = cachedData;
27
+ return Date.now() - timestamp <= ttl;
28
+ }
29
29
  }