@strkfarm/sdk 2.0.0-dev.9 → 2.0.0-staging.2
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.browser.global.js +111371 -93151
- package/dist/index.browser.mjs +27815 -32690
- package/dist/index.d.ts +1095 -2011
- package/dist/index.js +27425 -32309
- package/dist/index.mjs +27590 -32452
- package/package.json +6 -5
- package/src/data/ekubo-price-fethcer.abi.json +265 -0
- package/src/data/universal-vault.abi.json +20 -135
- package/src/dataTypes/address.ts +0 -7
- package/src/dataTypes/index.ts +3 -2
- package/src/dataTypes/mynumber.ts +141 -0
- package/src/global.ts +296 -288
- package/src/index.browser.ts +6 -5
- package/src/interfaces/common.tsx +324 -184
- package/src/modules/apollo-client-config.ts +28 -0
- package/src/modules/avnu.ts +4 -17
- package/src/modules/ekubo-pricer.ts +79 -0
- package/src/modules/ekubo-quoter.ts +11 -88
- package/src/modules/erc20.ts +21 -67
- package/src/modules/harvests.ts +26 -15
- package/src/modules/index.ts +11 -13
- package/src/modules/lst-apr.ts +0 -36
- package/src/modules/pragma.ts +23 -8
- package/src/modules/pricer-from-api.ts +150 -14
- package/src/modules/pricer.ts +2 -1
- package/src/modules/pricerBase.ts +2 -1
- package/src/node/deployer.ts +36 -1
- package/src/node/pricer-redis.ts +2 -1
- package/src/strategies/autoCompounderStrk.ts +1 -1
- package/src/strategies/base-strategy.ts +5 -22
- package/src/strategies/ekubo-cl-vault.tsx +2904 -2175
- package/src/strategies/factory.ts +165 -0
- package/src/strategies/index.ts +10 -11
- package/src/strategies/registry.ts +268 -0
- package/src/strategies/sensei.ts +416 -292
- package/src/strategies/universal-adapters/adapter-utils.ts +1 -5
- package/src/strategies/universal-adapters/baseAdapter.ts +153 -181
- package/src/strategies/universal-adapters/common-adapter.ts +77 -98
- package/src/strategies/universal-adapters/index.ts +1 -5
- package/src/strategies/universal-adapters/vesu-adapter.ts +218 -220
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +51 -58
- package/src/strategies/universal-lst-muliplier-strategy.tsx +1952 -992
- package/src/strategies/universal-strategy.tsx +1713 -1150
- package/src/strategies/vesu-rebalance.tsx +1189 -986
- package/src/utils/health-factor-math.ts +5 -11
- package/src/utils/index.ts +8 -9
- package/src/utils/strategy-utils.ts +57 -0
- package/src/data/extended-deposit.abi.json +0 -3613
- package/src/modules/ExtendedWrapperSDk/index.ts +0 -62
- package/src/modules/ExtendedWrapperSDk/types.ts +0 -311
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +0 -395
- package/src/modules/midas.ts +0 -159
- package/src/modules/token-market-data.ts +0 -202
- package/src/strategies/svk-strategy.ts +0 -247
- package/src/strategies/universal-adapters/adapter-optimizer.ts +0 -65
- package/src/strategies/universal-adapters/avnu-adapter.ts +0 -413
- package/src/strategies/universal-adapters/extended-adapter.ts +0 -972
- package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +0 -1306
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +0 -34
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +0 -77
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +0 -49
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +0 -370
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +0 -1379
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { ContractAddr, Web3Number } from '../dataTypes';
|
|
2
|
-
import { TokenInfo, IConfig } from '../interfaces';
|
|
3
|
-
import { PricerBase } from './pricerBase';
|
|
4
|
-
import { LSTAPRService } from './lst-apr';
|
|
5
|
-
import { Midas } from './midas';
|
|
6
|
-
import { SingleTokenInfo } from '../strategies/base-strategy';
|
|
7
|
-
import { logger } from '../utils/logger';
|
|
8
|
-
import { Contract } from 'starknet';
|
|
9
|
-
import { uint256 } from 'starknet';
|
|
10
|
-
import ERC4626Abi from '../data/erc4626.abi.json';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* TokenMarketData class that combines LST APR and Midas modules
|
|
14
|
-
* to provide unified APY, price, and TVL functions for tokens
|
|
15
|
-
*/
|
|
16
|
-
export class TokenMarketData {
|
|
17
|
-
private pricer: PricerBase;
|
|
18
|
-
private config: IConfig;
|
|
19
|
-
|
|
20
|
-
constructor(pricer: PricerBase, config: IConfig) {
|
|
21
|
-
this.pricer = pricer;
|
|
22
|
-
this.config = config;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Get APY for a token
|
|
27
|
-
* - If it's an LST token, returns LST APY
|
|
28
|
-
* - If it's a Midas token, returns Midas APY
|
|
29
|
-
* - Otherwise returns 0
|
|
30
|
-
* @param tokenInfo The token to get APY for
|
|
31
|
-
* @returns APY in absolute terms (not percentage)
|
|
32
|
-
*/
|
|
33
|
-
async getAPY(tokenInfo: TokenInfo): Promise<number> {
|
|
34
|
-
try {
|
|
35
|
-
// Check if it's an LST token
|
|
36
|
-
if (LSTAPRService.isLST(tokenInfo.address)) {
|
|
37
|
-
const underlying = LSTAPRService.getUnderlyingFromLST(tokenInfo.address);
|
|
38
|
-
const lstApr = await LSTAPRService.getLSTAPR(underlying.address);
|
|
39
|
-
logger.verbose(`TokenMarketData: LST APY for ${tokenInfo.symbol}: ${lstApr}`);
|
|
40
|
-
return lstApr;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Check if it's a Midas token by trying to get symbol
|
|
44
|
-
if (Midas.isSupported(tokenInfo.address)) {
|
|
45
|
-
const midasApy = await Midas.getAPY(tokenInfo.address);
|
|
46
|
-
logger.verbose(`TokenMarketData: Midas APY for ${tokenInfo.symbol}: ${midasApy}`);
|
|
47
|
-
return midasApy;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Default to 0 for unsupported tokens
|
|
51
|
-
logger.verbose(`TokenMarketData: No APY data available for ${tokenInfo.symbol}, returning 0`);
|
|
52
|
-
return 0;
|
|
53
|
-
} catch (error) {
|
|
54
|
-
logger.error(`TokenMarketData: Error getting APY for ${tokenInfo.symbol}:`, error);
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Get price for a token using the pricer module
|
|
61
|
-
* @param tokenInfo The token to get price for
|
|
62
|
-
* @returns Price as a number
|
|
63
|
-
* @throws Error if price is 0 or unavailable
|
|
64
|
-
*/
|
|
65
|
-
async getPrice(tokenInfo: TokenInfo): Promise<number> {
|
|
66
|
-
try {
|
|
67
|
-
const priceInfo = await this.pricer.getPrice(tokenInfo.symbol);
|
|
68
|
-
|
|
69
|
-
if (priceInfo.price === 0) {
|
|
70
|
-
throw new Error(`Price is 0 for token ${tokenInfo.symbol}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
logger.verbose(`TokenMarketData: Price for ${tokenInfo.symbol}: ${priceInfo.price}`);
|
|
74
|
-
return priceInfo.price;
|
|
75
|
-
} catch (error) {
|
|
76
|
-
logger.error(`TokenMarketData: Error getting price for ${tokenInfo.symbol}:`, error);
|
|
77
|
-
throw new Error(`Failed to get price for ${tokenInfo.symbol}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Get true price for a token
|
|
83
|
-
* - For LST tokens: Uses convert_to_assets to get true exchange rate
|
|
84
|
-
* - For Midas tokens: Uses Midas price API
|
|
85
|
-
* - For other tokens: Falls back to regular pricer
|
|
86
|
-
* @param tokenInfo The token to get true price for
|
|
87
|
-
* @returns True price as a number
|
|
88
|
-
* @throws Error if price is 0 or unavailable
|
|
89
|
-
*/
|
|
90
|
-
async getTruePrice(tokenInfo: TokenInfo): Promise<number> {
|
|
91
|
-
try {
|
|
92
|
-
// For LST tokens, use convert_to_assets
|
|
93
|
-
if (LSTAPRService.isLST(tokenInfo.address)) {
|
|
94
|
-
const lstABI = new Contract({
|
|
95
|
-
abi: ERC4626Abi,
|
|
96
|
-
address: tokenInfo.address.address,
|
|
97
|
-
providerOrAccount: this.config.provider
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
const price: any = await lstABI.call('convert_to_assets', [
|
|
101
|
-
uint256.bnToUint256((new Web3Number(1, tokenInfo.decimals)).toWei())
|
|
102
|
-
]);
|
|
103
|
-
const exchangeRate = Number(uint256.uint256ToBN(price).toString()) / Math.pow(10, tokenInfo.decimals);
|
|
104
|
-
|
|
105
|
-
if (exchangeRate === 0) {
|
|
106
|
-
throw new Error(`True price is 0 for LST token ${tokenInfo.symbol}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
logger.verbose(`TokenMarketData: LST true price for ${tokenInfo.symbol}: ${exchangeRate}`);
|
|
110
|
-
return exchangeRate;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// For Midas tokens, use Midas price API
|
|
114
|
-
if (Midas.isSupported(tokenInfo.address)) {
|
|
115
|
-
const midasPrice = await Midas.getPrice(tokenInfo.address);
|
|
116
|
-
|
|
117
|
-
if (midasPrice === 0) {
|
|
118
|
-
throw new Error(`True price is 0 for Midas token ${tokenInfo.symbol}`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
logger.verbose(`TokenMarketData: Midas true price for ${tokenInfo.symbol}: ${midasPrice}`);
|
|
122
|
-
return midasPrice;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// For other tokens, fall back to regular pricer
|
|
126
|
-
const price = await this.getPrice(tokenInfo);
|
|
127
|
-
|
|
128
|
-
if (price === 0) {
|
|
129
|
-
throw new Error(`True price is 0 for token ${tokenInfo.symbol}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
logger.verbose(`TokenMarketData: Regular price for ${tokenInfo.symbol}: ${price}`);
|
|
133
|
-
return price;
|
|
134
|
-
} catch (error) {
|
|
135
|
-
logger.error(`TokenMarketData: Error getting true price for ${tokenInfo.symbol}:`, error);
|
|
136
|
-
throw new Error(`Failed to get true price for ${tokenInfo.symbol}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Get TVL for a token
|
|
142
|
-
* - If it's a Midas token, returns Midas TVL data
|
|
143
|
-
* - Otherwise returns 0
|
|
144
|
-
* @param tokenInfo The token to get TVL for
|
|
145
|
-
* @returns TVL as SingleTokenInfo or 0
|
|
146
|
-
*/
|
|
147
|
-
async getTVL(tokenInfo: TokenInfo): Promise<SingleTokenInfo> {
|
|
148
|
-
// Check if it's a Midas token by trying to get TVL
|
|
149
|
-
if (Midas.isSupported(tokenInfo.address)) {
|
|
150
|
-
const midasTvl = await Midas.getTVL(tokenInfo.address);
|
|
151
|
-
|
|
152
|
-
// Handle different TVL response formats
|
|
153
|
-
let usdValue: number;
|
|
154
|
-
let nativeAmount: number;
|
|
155
|
-
|
|
156
|
-
if (typeof midasTvl === 'number') {
|
|
157
|
-
// Simple number format (e.g., mre7: 18193466)
|
|
158
|
-
usdValue = midasTvl;
|
|
159
|
-
nativeAmount = 0; // We don't have native amount in this format
|
|
160
|
-
} else if (typeof midasTvl === 'object' && 'usd' in midasTvl && 'native' in midasTvl) {
|
|
161
|
-
// Object format with usd and native (e.g., mre7btc: {usd: 998826, native: 9.3228})
|
|
162
|
-
usdValue = midasTvl.usd;
|
|
163
|
-
nativeAmount = midasTvl.native;
|
|
164
|
-
} else {
|
|
165
|
-
throw new Error(`Unexpected TVL format for ${tokenInfo.symbol}`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const tvlInfo: SingleTokenInfo = {
|
|
169
|
-
tokenInfo,
|
|
170
|
-
amount: Web3Number.fromWei(nativeAmount, tokenInfo.decimals),
|
|
171
|
-
usdValue
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
logger.verbose(`TokenMarketData: Midas TVL for ${tokenInfo.symbol}: USD=${usdValue}, Native=${nativeAmount}`);
|
|
175
|
-
return tvlInfo;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
tokenInfo,
|
|
180
|
-
amount: Web3Number.fromWei('0', tokenInfo.decimals),
|
|
181
|
-
usdValue: 0
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Check if a token is supported for APY data
|
|
187
|
-
* @param tokenInfo The token to check
|
|
188
|
-
* @returns True if the token has APY data available
|
|
189
|
-
*/
|
|
190
|
-
isAPYSupported(tokenInfo: TokenInfo): boolean {
|
|
191
|
-
return LSTAPRService.isLST(tokenInfo.address) || Midas.isSupported(tokenInfo.address);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Check if a token is supported for TVL data
|
|
196
|
-
* @param tokenInfo The token to check
|
|
197
|
-
* @returns True if the token has TVL data available
|
|
198
|
-
*/
|
|
199
|
-
isTVLSupported(tokenInfo: TokenInfo): boolean {
|
|
200
|
-
return Midas.isSupported(tokenInfo.address);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
@@ -1,247 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,65 +0,0 @@
|
|
|
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
|
-
}
|