@strkfarm/sdk 1.1.70 → 2.0.0-dev.1

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.
Files changed (53) hide show
  1. package/dist/cli.js +2 -2
  2. package/dist/cli.mjs +2 -2
  3. package/dist/index.browser.global.js +66861 -59746
  4. package/dist/index.browser.mjs +24970 -18579
  5. package/dist/index.d.ts +1969 -776
  6. package/dist/index.js +25264 -18850
  7. package/dist/index.mjs +25463 -19089
  8. package/package.json +80 -76
  9. package/src/data/extended-deposit.abi.json +3613 -0
  10. package/src/data/universal-vault.abi.json +135 -20
  11. package/src/dataTypes/address.ts +8 -1
  12. package/src/global.ts +240 -193
  13. package/src/interfaces/common.tsx +26 -2
  14. package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
  15. package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
  16. package/src/modules/ExtendedWrapperSDk/wrapper.ts +395 -0
  17. package/src/modules/avnu.ts +17 -4
  18. package/src/modules/ekubo-quoter.ts +98 -10
  19. package/src/modules/erc20.ts +67 -21
  20. package/src/modules/harvests.ts +16 -29
  21. package/src/modules/index.ts +5 -1
  22. package/src/modules/lst-apr.ts +36 -0
  23. package/src/modules/midas.ts +159 -0
  24. package/src/modules/pricer-from-api.ts +2 -2
  25. package/src/modules/pricer-lst.ts +1 -1
  26. package/src/modules/pricer.ts +3 -38
  27. package/src/modules/token-market-data.ts +202 -0
  28. package/src/node/deployer.ts +1 -36
  29. package/src/strategies/autoCompounderStrk.ts +1 -1
  30. package/src/strategies/base-strategy.ts +20 -3
  31. package/src/strategies/ekubo-cl-vault.tsx +123 -306
  32. package/src/strategies/index.ts +4 -1
  33. package/src/strategies/svk-strategy.ts +247 -0
  34. package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
  35. package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
  36. package/src/strategies/universal-adapters/avnu-adapter.ts +418 -0
  37. package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
  38. package/src/strategies/universal-adapters/common-adapter.ts +98 -77
  39. package/src/strategies/universal-adapters/extended-adapter.ts +544 -0
  40. package/src/strategies/universal-adapters/index.ts +5 -1
  41. package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
  42. package/src/strategies/universal-adapters/vesu-adapter.ts +220 -218
  43. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +924 -0
  44. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
  45. package/src/strategies/universal-lst-muliplier-strategy.tsx +707 -774
  46. package/src/strategies/universal-strategy.tsx +1098 -1180
  47. package/src/strategies/vesu-extended-strategy/services/operationService.ts +28 -0
  48. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
  49. package/src/strategies/vesu-extended-strategy/utils/constants.ts +48 -0
  50. package/src/strategies/vesu-extended-strategy/utils/helper.ts +374 -0
  51. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +992 -0
  52. package/src/strategies/vesu-rebalance.tsx +16 -19
  53. package/src/utils/health-factor-math.ts +11 -5
@@ -5,4 +5,7 @@ export * from './base-strategy';
5
5
  export * from './sensei';
6
6
  export * from './universal-adapters';
7
7
  export * from './universal-strategy';
8
- export * from './universal-lst-muliplier-strategy';
8
+ export * from './universal-lst-muliplier-strategy';
9
+ export * from './vesu-extended-strategy/vesu-extended-strategy';
10
+ export * from './vesu-extended-strategy/utils/config.runtime';
11
+ export * from './vesu-extended-strategy/utils/helper';
@@ -0,0 +1,247 @@
1
+ import { ContractAddr, Web3Number } from "@/dataTypes";
2
+ import { IConfig, IStrategyMetadata, TokenInfo, VaultPosition } from "@/interfaces";
3
+ import { PricerBase } from "@/modules/pricerBase";
4
+ import { ERC20 } from "@/modules";
5
+ import { BaseStrategy, SingleActionAmount, SingleTokenInfo } from "./base-strategy";
6
+ import { Call, Contract, num } from "starknet";
7
+ import { assert, LeafData, logger, StandardMerkleTree } from "@/utils";
8
+ import { UniversalStrategySettings } from "./universal-strategy";
9
+ import { UNIVERSAL_MANAGE_IDS } from "./universal-strategy";
10
+ import UniversalVaultAbi from '../data/universal-vault.abi.json';
11
+ import ManagerAbi from '../data/vault-manager.abi.json';
12
+ import { ManageCall, PositionInfo } from "./universal-adapters";
13
+
14
+ /**
15
+ * Base class for all SVK (Starknet Vault Kit) strategies.
16
+ * Contains common functions that are shared across all SVK strategies.
17
+ */
18
+ export abstract class SVKStrategy<S extends UniversalStrategySettings>
19
+ extends BaseStrategy<SingleTokenInfo, SingleActionAmount> {
20
+
21
+ /** Contract address of the strategy */
22
+ readonly address: ContractAddr;
23
+ /** Pricer instance for token price calculations */
24
+ readonly pricer: PricerBase;
25
+ /** Metadata containing strategy information */
26
+ readonly metadata: IStrategyMetadata<S>;
27
+ /** Contract instance for interacting with the strategy */
28
+ readonly contract: Contract;
29
+ /** Manager contract instance for merkle verification */
30
+ readonly managerContract: Contract;
31
+ /** Cached merkle tree instance */
32
+ merkleTree: StandardMerkleTree | undefined;
33
+
34
+ constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<S>) {
35
+ super(config);
36
+ this.pricer = pricer;
37
+ this.metadata = metadata;
38
+ this.address = metadata.address;
39
+
40
+ this.contract = new Contract({
41
+ abi: UniversalVaultAbi,
42
+ address: this.address.address,
43
+ providerOrAccount: this.config.provider
44
+ });
45
+
46
+ this.managerContract = new Contract({
47
+ abi: ManagerAbi,
48
+ address: this.metadata.additionalInfo.manager.address,
49
+ providerOrAccount: this.config.provider
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Returns the asset token for this strategy
55
+ */
56
+ asset(): TokenInfo {
57
+ return this.metadata.depositTokens[0];
58
+ }
59
+
60
+ /**
61
+ * Returns the unused balance in the vault allocator.
62
+ * Note: This function is common for any SVK strategy.
63
+ */
64
+ async getUnusedBalance(): Promise<SingleTokenInfo> {
65
+ const balance = await (new ERC20(this.config)).balanceOf(
66
+ this.asset().address,
67
+ this.metadata.additionalInfo.vaultAllocator,
68
+ this.asset().decimals
69
+ );
70
+ const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
71
+ const usdValue = Number(balance.toFixed(6)) * price.price;
72
+ return {
73
+ tokenInfo: this.asset(),
74
+ amount: balance,
75
+ usdValue
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Bridges liquidity from the vault allocator back to the vault.
81
+ * Note: This function is common for any SVK strategy.
82
+ */
83
+ async getBringLiquidityCall(params: { amount: Web3Number }): Promise<Call> {
84
+ // Find approve leaf adapter
85
+ const approveAdapter = this.metadata.additionalInfo.leafAdapters.find(
86
+ adapter => adapter().leaves.find(leaf => leaf.readableId === UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY)
87
+ );
88
+
89
+ if (!approveAdapter) {
90
+ throw new Error(`${this.getTag()}::getBringLiquidityCall: approve adapter not found`);
91
+ }
92
+
93
+ // Find bring liquidity leaf adapter
94
+ const bringLiquidityAdapter = this.metadata.additionalInfo.leafAdapters.find(
95
+ adapter => adapter().leaves.find(leaf => leaf.readableId === UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY)
96
+ );
97
+
98
+ if (!bringLiquidityAdapter) {
99
+ throw new Error(`${this.getTag()}::getBringLiquidityCall: bring liquidity adapter not found`);
100
+ }
101
+
102
+ // Get proofs
103
+ const tree = this.getMerkleTree();
104
+ const proofGroups: string[][] = [];
105
+ for (const [i, v] of tree.entries()) {
106
+ if (v.readableId === UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY ||
107
+ v.readableId === UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY) {
108
+ proofGroups.push(tree.getProof(i));
109
+ }
110
+ }
111
+
112
+ // Construct calls
113
+ logger.verbose("approve adapter amount", params.amount);
114
+ const approveCalls = await approveAdapter().callConstructor({ amount: params.amount });
115
+ const bringLiquidityCalls = await bringLiquidityAdapter().callConstructor({ amount: params.amount });
116
+
117
+ // Combine into final call
118
+ return this.getManageCall(proofGroups, [...approveCalls, ...bringLiquidityCalls]);
119
+ }
120
+
121
+ /**
122
+ * Gets all leaves from all leaf adapters.
123
+ * Note: This function is common for any SVK strategy.
124
+ */
125
+ getAllLeaves(): LeafData[] {
126
+ const leaves = this.metadata.additionalInfo.leafAdapters.map(adapter => adapter());
127
+ const _leaves: LeafData[] = [];
128
+ leaves.forEach((_l) => {
129
+ _leaves.push(..._l.leaves);
130
+ });
131
+ return _leaves;
132
+ }
133
+
134
+ /**
135
+ * Builds and caches the merkle tree from all leaf adapters.
136
+ * Note: This function is common for any SVK strategy.
137
+ */
138
+ getMerkleTree(): StandardMerkleTree {
139
+ if (this.merkleTree) return this.merkleTree;
140
+ const _leaves = this.getAllLeaves();
141
+ const standardTree = StandardMerkleTree.of(_leaves);
142
+ this.merkleTree = standardTree;
143
+ return standardTree;
144
+ }
145
+
146
+ /**
147
+ * Gets the merkle root of the tree.
148
+ * Note: This function is common for any SVK strategy.
149
+ */
150
+ getMerkleRoot(): string {
151
+ return this.getMerkleTree().root;
152
+ }
153
+
154
+ /**
155
+ * Combines proofs and manage calls into a single Starknet call.
156
+ * Note: This function is common for any SVK strategy.
157
+ */
158
+ getManageCall(proofGroups: string[][], manageCalls: ManageCall[]): Call {
159
+ assert(
160
+ proofGroups.length == manageCalls.length,
161
+ `Proof IDs and Manage Calls length mismatch: ${proofGroups.length} != ${manageCalls.length}`
162
+ );
163
+
164
+ return this.managerContract.populate('manage_vault_with_merkle_verification', {
165
+ proofs: proofGroups.map(group => group),
166
+ decoder_and_sanitizers: manageCalls.map(call => call.sanitizer.address),
167
+ targets: manageCalls.map(call => call.call.contractAddress.address),
168
+ selectors: manageCalls.map(call => call.call.selector),
169
+ calldatas: manageCalls.map(call => call.call.calldata),
170
+ });
171
+ }
172
+
173
+ /**
174
+ * Creates a call to set the merkle root on the manager contract.
175
+ * Note: This function is common for any SVK strategy.
176
+ */
177
+ getSetManagerCall(strategist: ContractAddr, root = this.getMerkleRoot()): Call {
178
+ return this.managerContract.populate('set_manage_root', [
179
+ strategist.address,
180
+ num.getHexString(root)
181
+ ]);
182
+ }
183
+
184
+ /**
185
+ * Returns a tag for logging purposes.
186
+ * Should be overridden by subclasses to provide strategy-specific tags.
187
+ */
188
+ abstract getTag(): string;
189
+
190
+
191
+ /**
192
+ * Returns the positions in the vault.
193
+ * @returns An array of VaultPosition objects representing the positions in the vault.
194
+ */
195
+ async getVaultPositions(): Promise<VaultPosition[]> {
196
+ const positions = await Promise.all(
197
+ this.metadata.additionalInfo.adapters.map(adapter => adapter.adapter.getPositions())
198
+ )
199
+ return positions.flat().map((position) => ({
200
+ amount: position.amount,
201
+ usdValue: position.usdValue,
202
+ remarks: position.remarks ?? '',
203
+ token: position.tokenInfo,
204
+ protocol: position.protocol
205
+ }))
206
+ }
207
+
208
+ async getHealthFactors(): Promise<number[]> {
209
+ return Promise.all(this.metadata.additionalInfo.adapters.map(adapter => adapter.adapter.getHealthFactor()));
210
+ }
211
+
212
+ // todo undo this
213
+ async netAPY(): Promise<{ net: number; splits: { apy: number; id: string; }[]; }> {
214
+ const allPositions: PositionInfo[] = [];
215
+ for (let adapter of this.metadata.additionalInfo.adapters) {
216
+ const positions = await adapter.adapter.getPositions();
217
+ allPositions.push(...positions);
218
+ }
219
+
220
+ const totalHoldingsUSDValue = allPositions.reduce((acc, curr) => acc + curr.usdValue, 0);
221
+ let weightedAPYs = allPositions.reduce((acc, curr) => acc + curr.apy.apy * curr.usdValue, 0);
222
+ const netAPY = weightedAPYs / totalHoldingsUSDValue;
223
+ return {
224
+ net: netAPY,
225
+ splits: allPositions.map(p => ({apy: p.apy.apy, id: p.remarks ?? ''}))
226
+ };
227
+ }
228
+
229
+ async getPrevAUM() {
230
+ const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
231
+ const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
232
+ logger.verbose(`${this.getTag()} Prev AUM: ${prevAum}`);
233
+ return prevAum;
234
+ }
235
+
236
+ async maxDepositables() {
237
+ const maxDepositables = await Promise.all(this.metadata.additionalInfo.adapters.map(adapter => adapter.adapter.maxDeposit()));
238
+ return maxDepositables;
239
+ }
240
+
241
+ async maxWithdrawables() {
242
+ const maxWithdrawables = await Promise.all(this.metadata.additionalInfo.adapters.map(adapter => adapter.adapter.maxWithdraw()));
243
+ return maxWithdrawables;
244
+ }
245
+
246
+ }
247
+
@@ -0,0 +1,65 @@
1
+ import { logger } from "@/utils";
2
+ import { BaseAdapter, DepositParams, WithdrawParams } from "./baseAdapter";
3
+ import { Web3Number } from "@/dataTypes";
4
+
5
+ export class AdapterOptimizer {
6
+
7
+ // write a export function to compute the adapter to use
8
+ // for a given withdraw/deposit action. It can be one or more adapters.
9
+ // Key decision factors:
10
+ // 1. The netAPY of the adapter is low compared to others (exhaust this first before using others)
11
+ // 2. Prefer one adapter over multiple adapters
12
+ static async getAdapterToUse(adapters: BaseAdapter<DepositParams, WithdrawParams>[], isDeposit: boolean, amount: Web3Number): Promise<BaseAdapter<DepositParams, WithdrawParams>[]> {
13
+ logger.verbose(`${this.name}::getAdapterToUse: adapters: ${JSON.stringify(adapters)}, isDeposit: ${isDeposit}, amount: ${amount.toFixed(9)}`);
14
+ const netAPYs = await Promise.all(adapters.map(a => a.getNetAPY()));
15
+ const indexAndNetAPYsArr = netAPYs.map((apy, index) => [index, apy]);
16
+ logger.verbose(`${this.name}::getAdapterToUse: netAPYs: ${JSON.stringify(netAPYs)}`);
17
+ // if is deposit
18
+ if (isDeposit) {
19
+ // sort apys by descending
20
+ const sortedNetAPYs = indexAndNetAPYsArr.sort((a, b) => (b[1] || 0) - (a[1] || 0));
21
+ logger.verbose(`${this.name}::getAdapterToUse: sortedNetAPYs: ${JSON.stringify(sortedNetAPYs)}`);
22
+
23
+ // get max depositables
24
+ const adaptersToUse: BaseAdapter<DepositParams, WithdrawParams>[] = [];
25
+ let remainingAmount = amount;
26
+ for (const [index, _] of sortedNetAPYs) {
27
+ const adapter = adapters[index];
28
+ const maxDepositable = await adapter.maxDeposit(amount);
29
+ if (maxDepositable.amount.gt(0)) {
30
+ adaptersToUse.push(adapter);
31
+ remainingAmount = remainingAmount.minus(maxDepositable.amount).minimum(0);
32
+ }
33
+
34
+ if (remainingAmount.lte(0)) {
35
+ break;
36
+ }
37
+ }
38
+
39
+ return adaptersToUse;
40
+ } else {
41
+ // sort apys by ascending
42
+ const sortedNetAPYs = indexAndNetAPYsArr.sort((a, b) => (a[1] || 0) - (b[1] || 0));
43
+ logger.verbose(`${this.name}::getAdapterToUse: sortedNetAPYs: ${JSON.stringify(sortedNetAPYs)}`);
44
+
45
+ // get max withdrawables
46
+ const adaptersToUse: BaseAdapter<DepositParams, WithdrawParams>[] = [];
47
+ let remainingAmount = amount.abs();
48
+ for (const [index, _] of sortedNetAPYs) {
49
+ const adapter = adapters[index];
50
+ const maxWithdrawable = await adapter.maxWithdraw();
51
+ logger.verbose(`${this.name}::getAdapterToUse: maxWithdrawable: ${JSON.stringify(maxWithdrawable)}, adapter: ${adapter.name}, remainingAmount: ${remainingAmount}`);
52
+ if (maxWithdrawable.amount.gt(0)) {
53
+ adaptersToUse.push(adapter);
54
+ remainingAmount = remainingAmount.minus(maxWithdrawable.amount).minimum(0);
55
+ }
56
+
57
+ if (remainingAmount.lte(0)) {
58
+ break;
59
+ }
60
+ }
61
+
62
+ return adaptersToUse;
63
+ }
64
+ }
65
+ }
@@ -2,6 +2,8 @@ import { ContractAddr } from "@/dataTypes";
2
2
 
3
3
  // Zellic audited
4
4
  export const SIMPLE_SANITIZER = ContractAddr.from('0x5a2e3ceb3da368b983a8717898427ab7b6daf04014b70f321e777f9aad940b4');
5
+ export const EXTENDED_SANITIZER = ContractAddr.from('0x65891708362b24dcf4c40c8e218cce6e82d1d6b3a3404c9ab00a48f08e2c110');
6
+ export const AVNU_LEGACY_SANITIZER = ContractAddr.from('0x0656fBE853f116DD53956176a553eDe8fE65632252f8aceB50C1B9B6c8237309');
5
7
  // Without flashloan options
6
8
  export const SIMPLE_SANITIZER_V2 = ContractAddr.from('0x7b6f98311af8aa425278570e62abf523e6462eaa01a38c1feab9b2f416492e2');
7
9
  export const VESU_V2_MODIFY_POSITION_SANITIZER = ContractAddr.from('0x04Bf71F2BD9D6F8819057c9dD524F0d5fbc38317C00500d7b9a0FdCf01195066');
@@ -9,7 +11,9 @@ export const SIMPLE_SANITIZER_VESU_V1_DELEGATIONS = ContractAddr.from('0x5643d54
9
11
  export const PRICE_ROUTER = ContractAddr.from('0x05e83Fa38D791d2dba8E6f487758A9687FfEe191A6Cf8a6c5761ab0a110DB837');
10
12
  export const AVNU_MIDDLEWARE = ContractAddr.from('0x4a7972ed3f5d1e74a6d6c4a8f467666953d081c8f2270390cc169d50d17cb0d');
11
13
  export const AVNU_EXCHANGE = ContractAddr.from('0x04270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f');
12
-
14
+ export const AVNU_EXCHANGE_FOR_LEGACY_USDC = ContractAddr.from('0x7bffc7f6bda62b7bee9b7880579633a38f7ef910e0ad5e686b0b8712e216a19')
15
+ export const AVNU_QUOTE_URL = "https://starknet.api.avnu.fi/swap/v3/quotes";
16
+ export const EXTENDED_CONTRACT = ContractAddr.from('0x062da0780fae50d68cecaa5a051606dc21217ba290969b302db4dd99d2e9b470');
13
17
  export const VESU_SINGLETON = ContractAddr.from('0x000d8d6dfec4d33bfb6895de9f3852143a17c6f92fd2a21da3d6924d34870160');
14
18
  export function toBigInt(value: string | number): bigint {
15
19
  if (typeof value === 'string') {