@strkfarm/sdk 2.0.0-dev.5 → 2.0.0-dev.51

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 (80) hide show
  1. package/dist/cli.js +190 -36
  2. package/dist/cli.mjs +188 -34
  3. package/dist/index.browser.global.js +118889 -92229
  4. package/dist/index.browser.mjs +13381 -11153
  5. package/dist/index.d.ts +2284 -1938
  6. package/dist/index.js +13794 -11360
  7. package/dist/index.mjs +14253 -11843
  8. package/package.json +59 -60
  9. package/src/data/avnu.abi.json +840 -0
  10. package/src/data/ekubo-price-fethcer.abi.json +265 -0
  11. package/src/data/redeem-request-nft.abi.json +752 -0
  12. package/src/data/universal-vault.abi.json +8 -7
  13. package/src/dataTypes/_bignumber.ts +13 -4
  14. package/src/dataTypes/bignumber.browser.ts +10 -1
  15. package/src/dataTypes/bignumber.node.ts +10 -1
  16. package/src/dataTypes/index.ts +3 -2
  17. package/src/dataTypes/mynumber.ts +141 -0
  18. package/src/global.ts +280 -233
  19. package/src/index.browser.ts +2 -1
  20. package/src/interfaces/common.tsx +229 -6
  21. package/src/modules/apollo-client-config.ts +28 -0
  22. package/src/modules/avnu.ts +21 -12
  23. package/src/modules/ekubo-pricer.ts +99 -0
  24. package/src/modules/ekubo-quoter.ts +48 -30
  25. package/src/modules/erc20.ts +17 -0
  26. package/src/modules/harvests.ts +43 -29
  27. package/src/modules/index.ts +2 -1
  28. package/src/modules/pragma.ts +23 -8
  29. package/src/modules/pricer-avnu-api.ts +114 -0
  30. package/src/modules/pricer-from-api.ts +159 -15
  31. package/src/modules/pricer-lst.ts +1 -1
  32. package/src/modules/pricer-quote-utils.ts +54 -0
  33. package/src/modules/pricer.ts +157 -54
  34. package/src/modules/pricerBase.ts +2 -1
  35. package/src/modules/zkLend.ts +3 -2
  36. package/src/node/deployer.ts +36 -1
  37. package/src/node/pricer-redis.ts +3 -1
  38. package/src/strategies/base-strategy.ts +168 -16
  39. package/src/strategies/constants.ts +8 -3
  40. package/src/strategies/ekubo-cl-vault.tsx +1048 -355
  41. package/src/strategies/factory.ts +199 -0
  42. package/src/strategies/index.ts +5 -3
  43. package/src/strategies/registry.ts +262 -0
  44. package/src/strategies/sensei.ts +354 -10
  45. package/src/strategies/svk-strategy.ts +292 -31
  46. package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +1261 -0
  47. package/src/strategies/types.ts +4 -0
  48. package/src/strategies/universal-adapters/adapter-utils.ts +4 -1
  49. package/src/strategies/universal-adapters/avnu-adapter.ts +196 -272
  50. package/src/strategies/universal-adapters/baseAdapter.ts +263 -251
  51. package/src/strategies/universal-adapters/common-adapter.ts +206 -203
  52. package/src/strategies/universal-adapters/index.ts +10 -8
  53. package/src/strategies/universal-adapters/svk-troves-adapter.ts +511 -0
  54. package/src/strategies/universal-adapters/token-transfer-adapter.ts +200 -0
  55. package/src/strategies/universal-adapters/vesu-adapter.ts +120 -82
  56. package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +525 -0
  57. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +866 -860
  58. package/src/strategies/universal-adapters/vesu-position-common.ts +258 -0
  59. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +18 -3
  60. package/src/strategies/universal-lst-muliplier-strategy.tsx +895 -416
  61. package/src/strategies/universal-strategy.tsx +1332 -1173
  62. package/src/strategies/vesu-rebalance.tsx +254 -153
  63. package/src/strategies/yoloVault.ts +1096 -0
  64. package/src/utils/cacheClass.ts +11 -2
  65. package/src/utils/health-factor-math.ts +33 -1
  66. package/src/utils/index.ts +3 -1
  67. package/src/utils/logger.browser.ts +22 -4
  68. package/src/utils/logger.node.ts +259 -24
  69. package/src/utils/starknet-call-parser.ts +1036 -0
  70. package/src/utils/strategy-utils.ts +61 -0
  71. package/src/modules/ExtendedWrapperSDk/index.ts +0 -62
  72. package/src/modules/ExtendedWrapperSDk/types.ts +0 -311
  73. package/src/modules/ExtendedWrapperSDk/wrapper.ts +0 -395
  74. package/src/strategies/universal-adapters/extended-adapter.ts +0 -662
  75. package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
  76. package/src/strategies/vesu-extended-strategy/services/operationService.ts +0 -34
  77. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +0 -77
  78. package/src/strategies/vesu-extended-strategy/utils/constants.ts +0 -49
  79. package/src/strategies/vesu-extended-strategy/utils/helper.ts +0 -372
  80. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +0 -1140
@@ -5,6 +5,7 @@ interface CacheData {
5
5
  }
6
6
  export class CacheClass {
7
7
  readonly cache: Map<string, CacheData> = new Map();
8
+ isCacheEnabled: boolean = true;
8
9
 
9
10
  setCache(key: string, data: any, ttl: number = 60000): void {
10
11
  const timestamp = Date.now();
@@ -13,7 +14,7 @@ export class CacheClass {
13
14
 
14
15
  getCache<T>(key: string): T | null {
15
16
  const cachedData = this.cache.get(key);
16
- if (!cachedData || !this.isCacheValid(key)) {
17
+ if (!cachedData || !this.isCacheValid(key) || !this.isCacheEnabled) {
17
18
  return null;
18
19
  }
19
20
  return cachedData.data;
@@ -26,4 +27,12 @@ export class CacheClass {
26
27
  const { timestamp, ttl } = cachedData;
27
28
  return Date.now() - timestamp <= ttl;
28
29
  }
29
- }
30
+
31
+ disableCache(): void {
32
+ this.isCacheEnabled = false;
33
+ }
34
+
35
+ enableCache(): void {
36
+ this.isCacheEnabled = true;
37
+ }
38
+ }
@@ -82,8 +82,40 @@ export class HealthFactorMath {
82
82
  // => X * (HF - maxLTV) = 1 * cp * maxLTV
83
83
  // => X = 1 * cp * maxLTV / (HF - maxLTV)
84
84
  const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
85
+ logger.verbose(`HealthFactorMath: Max debt amount numerator: ${numerator.toNumber()}, collateralAmount: ${collateralAmount.toNumber()}, collateralPrice: ${collateralPrice}, maxLTV: ${maxLTV}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
85
86
  const denominator = targetHF * debtPrice;
87
+ logger.verbose(`HealthFactorMath: Max debt amount denominator: ${denominator}, targetHF: ${targetHF}, debtPrice: ${debtPrice}`);
86
88
  const debtAmount = numerator.dividedBy(denominator);
89
+ logger.verbose(`HealthFactorMath: Max debt amount: ${debtAmount.toNumber()}, numerator: ${numerator.toNumber()}, denominator: ${denominator}`);
87
90
  return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
88
91
  }
89
- }
92
+
93
+ static calculateDebtReductionAmountForWithdrawal = (
94
+ debtAmount: Web3Number,
95
+ collateralAmount: Web3Number,
96
+ maxLtv: number,
97
+ targetHF: number,
98
+ withdrawalAmount: Web3Number,
99
+ collateralPrice: number,
100
+ debtPrice: number,
101
+ collateralTokenInfo: TokenInfo,
102
+ debtTokenInfo: TokenInfo,
103
+ ) => {
104
+ const idealLTV = maxLtv / targetHF;
105
+ // formulae
106
+ // dDebt is change is debt.
107
+ // (current debt - dDebt) * debtPrice / (current collateral - withdrawAmount - (dDebt * debtPrice / collPrice)) = idealLTV
108
+ // (current debt - dDebt) * debtPrice = idealLTV * (current collateral - withdrawAmount) - (idealLTV * dDebt * debtPrice / collPrice))
109
+ // dDebt * (idealLTV * debtPrice / collPrice - debtPrice) = idealLTV * (current collateral - withdrawAmount) - current debt * debtPrice
110
+ // dDebt = (idealLTV * (current collateral - withdrawAmount) - current debt * debtPrice) / (idealLTV * debtPrice / collPrice - debtPrice)
111
+ const _dDebt = (collateralAmount.minus(withdrawalAmount).multipliedBy(idealLTV).minus(debtAmount.multipliedBy(debtPrice)).dividedBy((idealLTV * debtPrice / collateralPrice) - debtPrice));
112
+ const dDebt = Web3Number.fromWei(_dDebt.toWei(), debtTokenInfo.decimals);
113
+ if (dDebt.lessThan(0)) {
114
+ return { deltadebtAmountUnits: null };
115
+ }
116
+ if (dDebt.greaterThan(debtAmount)) {
117
+ return { deltadebtAmountUnits: debtAmount };
118
+ }
119
+ return { deltadebtAmountUnits: dDebt};
120
+ }
121
+ }
@@ -1,6 +1,8 @@
1
-
2
1
  export * from '@/utils/logger';
3
2
  export * from './oz-merkle';
3
+ export * from "./strategy-utils";
4
+ export * from "./starknet-call-parser";
5
+ export * from "./health-factor-math";
4
6
 
5
7
  // Utility type to make all optional properties required
6
8
  export type RequiredFields<T> = {
@@ -4,6 +4,20 @@ interface LeveledLogMethod {
4
4
  (message: any): void
5
5
  }
6
6
 
7
+ export type LoggerLevel = "error" | "warn" | "info" | "verbose" | "debug";
8
+
9
+ export interface LoggerConfig {
10
+ level?: LoggerLevel;
11
+ consoleLevel?: LoggerLevel;
12
+ fileLevel?: LoggerLevel;
13
+ filePath?: string;
14
+ enableConsole?: boolean;
15
+ enableFile?: boolean;
16
+ colorizeConsole?: boolean;
17
+ shortErrorsInConsole?: boolean;
18
+ emitConfigLog?: boolean;
19
+ }
20
+
7
21
  interface MyLogger {
8
22
  error: LeveledLogMethod;
9
23
  warn: LeveledLogMethod;
@@ -13,8 +27,12 @@ interface MyLogger {
13
27
  }
14
28
 
15
29
  export const logger: MyLogger = {
16
- ...console,
17
- verbose(message: string) {
18
- console.log(`[VERBOSE] ${message}`);
19
- }
30
+ ...console,
31
+ verbose(message: string) {
32
+ console.log(`[VERBOSE] ${message}`);
33
+ }
20
34
  };
35
+
36
+ export function configureLogger(_config: LoggerConfig = {}): MyLogger {
37
+ return logger;
38
+ }
@@ -1,35 +1,270 @@
1
+ import fs from "fs";
2
+ import path from "path";
1
3
  import winston, { format } from "winston";
2
4
 
5
+ export type LoggerLevel = "error" | "warn" | "info" | "verbose" | "debug";
6
+
7
+ export interface LoggerConfig {
8
+ level?: LoggerLevel;
9
+ consoleLevel?: LoggerLevel;
10
+ fileLevel?: LoggerLevel;
11
+ filePath?: string;
12
+ enableConsole?: boolean;
13
+ enableFile?: boolean;
14
+ colorizeConsole?: boolean;
15
+ shortErrorsInConsole?: boolean;
16
+ emitConfigLog?: boolean;
17
+ }
18
+
3
19
  const colors = {
4
20
  error: "red",
5
21
  warn: "yellow",
6
22
  info: "blue",
7
- verbose: "white",
8
- debug: "white",
23
+ verbose: "cyan",
24
+ debug: "gray",
9
25
  };
10
-
11
- // Add custom colors to Winston
12
26
  winston.addColors(colors);
13
27
 
14
- export const logger = winston.createLogger({
15
- level: "debug", // Set the minimum logging level
16
- format: format.combine(
17
- format.colorize({ all: true }), // Apply custom colors
18
- format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), // Add timestamp to log messages
19
- format.printf(({ timestamp, level, message, ...meta }) => {
20
- let msg = `${timestamp} ${level}: ${message}`;
21
- // Print stack trace if error is passed
22
- if (meta && meta[Symbol.for("splat")]) {
23
- for (const arg of meta[Symbol.for("splat")]) {
24
- if (arg instanceof Error) {
25
- msg += `\n${arg.stack}`;
26
- }
27
- }
28
+ const stringifyUnknown = (value: unknown): string => {
29
+ if (typeof value === "string") return value;
30
+ if (typeof value === "undefined") return "undefined";
31
+ if (value === null) return "null";
32
+ if (value instanceof Error) return value.message || value.name || "Error";
33
+ try {
34
+ const encoded = JSON.stringify(value, (_, v) =>
35
+ typeof v === "bigint" ? v.toString() : v,
36
+ );
37
+ return encoded ?? String(value);
38
+ } catch {
39
+ return String(value);
40
+ }
41
+ };
42
+
43
+ const stripAnsi = (text: unknown): string =>
44
+ stringifyUnknown(text).replace(/\u001b\[[0-9;]*m/g, "");
45
+
46
+ const escapeValue = (value: string): string =>
47
+ value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
48
+
49
+ const escapeMessageValue = (value: string): string =>
50
+ value
51
+ .replace(/\\/g, "\\\\")
52
+ .replace(/"/g, "'")
53
+ .replace(/\n/g, "\\n");
54
+
55
+ const ANSI = {
56
+ reset: "\x1b[0m",
57
+ red: "\x1b[31m",
58
+ yellow: "\x1b[33m",
59
+ green: "\x1b[32m",
60
+ };
61
+
62
+ const paint = (text: string, color: string): string =>
63
+ `${color}${text}${ANSI.reset}`;
64
+
65
+ const highlightRoutes = (text: string): string =>
66
+ text.replace(/\b[A-Z][A-Z0-9_]{2,}\b/g, (token) => paint(token, ANSI.yellow));
67
+
68
+ const highlightCases = (text: string): string =>
69
+ text.replace(/\[[A-Z][A-Z0-9_]+\]/g, (token) => paint(token, ANSI.green));
70
+
71
+ const colorizeMessageForConsole = (message: string): string => {
72
+ const hasExtendedTradeContext =
73
+ /\bEXTENDED_(LIMIT|MARKET)_(BUY|SELL)\b/.test(message) ||
74
+ /\bEXTENDED_(INCREASE|DECREASE)_LEVER\b/.test(message);
75
+
76
+ if (hasExtendedTradeContext && /\b(SUCCESS|SUCCEEDED|FILLED)\b/i.test(message)) {
77
+ return paint(highlightRoutes(message), ANSI.green);
78
+ }
79
+
80
+ if (
81
+ hasExtendedTradeContext &&
82
+ /\b(INITIATED|PENDING|SUBMITTED|RETRY|PARTIAL)\b/i.test(message)
83
+ ) {
84
+ return paint(highlightRoutes(message), ANSI.yellow);
85
+ }
86
+
87
+ // Failure paths should dominate visually.
88
+ if (/\b(fail|failed|failure|error)\b/i.test(message)) {
89
+ return paint(highlightRoutes(highlightCases(message)), ANSI.red);
90
+ }
91
+
92
+ if (/Transaction sent/i.test(message)) {
93
+ return paint(message, ANSI.yellow);
94
+ }
95
+
96
+ if (/Transaction succeeded/i.test(message)) {
97
+ return paint(message, ANSI.green);
98
+ }
99
+
100
+ if (/Detected \d+ case\(s\)/i.test(message)) {
101
+ return paint(highlightRoutes(highlightCases(message)), ANSI.green);
102
+ }
103
+
104
+ if (/_executeStandardCase route/i.test(message)) {
105
+ return paint(highlightRoutes(message), ANSI.green);
106
+ }
107
+
108
+ // For route-heavy messages, keep routes highlighted in yellow.
109
+ if (/\broute\b/i.test(message)) {
110
+ return highlightRoutes(message);
111
+ }
112
+
113
+ return message;
114
+ };
115
+
116
+ const FIXED_TAG_WIDTH = 10;
117
+
118
+ const toFixedTag = (rawTag: string): string => {
119
+ const compact = rawTag.replace(/[^A-Za-z0-9_-]/g, "");
120
+ if (!compact) return "general".slice(0, FIXED_TAG_WIDTH).padEnd(FIXED_TAG_WIDTH, " ");
121
+ return compact.slice(0, FIXED_TAG_WIDTH).padEnd(FIXED_TAG_WIDTH, " ");
122
+ };
123
+
124
+ const extractTagAndMessage = (rawMessage: string): { tag: string; body: string } => {
125
+ const normalized = stripAnsi(rawMessage).trim();
126
+
127
+ const bracketTagMatch = normalized.match(/^\[([^\]]+)\]\s*(.*)$/);
128
+ if (bracketTagMatch) {
129
+ return {
130
+ tag: toFixedTag(bracketTagMatch[1]),
131
+ body: bracketTagMatch[2] || normalized,
132
+ };
133
+ }
134
+
135
+ const scopeTagMatch = normalized.match(/^([A-Za-z0-9_-]+)::\s*(.*)$/);
136
+ if (scopeTagMatch) {
137
+ return {
138
+ tag: toFixedTag(scopeTagMatch[1]),
139
+ body: scopeTagMatch[2] || normalized,
140
+ };
141
+ }
142
+
143
+ return {
144
+ tag: toFixedTag("general"),
145
+ body: normalized,
146
+ };
147
+ };
148
+
149
+ const getStackFromMeta = (
150
+ stack: unknown,
151
+ meta: Record<string, unknown>,
152
+ ): string | undefined => {
153
+ if (typeof stack === "string" && stack.length > 0) {
154
+ return stack;
155
+ }
156
+ const splat = meta[Symbol.for("splat") as unknown as keyof typeof meta] as unknown;
157
+ if (Array.isArray(splat)) {
158
+ for (const item of splat) {
159
+ if (item instanceof Error && item.stack) {
160
+ return item.stack;
28
161
  }
29
- return msg;
30
- })
31
- ),
32
- transports: [
33
- new winston.transports.Console(), // Output logs to the console
34
- ],
162
+ }
163
+ }
164
+ return undefined;
165
+ };
166
+
167
+ const DEFAULT_LEVEL = (
168
+ process.env.LOG_LEVEL ||
169
+ process.env.SDK_LOG_LEVEL ||
170
+ "debug"
171
+ ).toLowerCase() as LoggerLevel;
172
+
173
+ const DEFAULT_CONSOLE_LEVEL = (
174
+ process.env.LOG_CONSOLE_LEVEL || "info"
175
+ ).toLowerCase() as LoggerLevel;
176
+
177
+ const DEFAULT_FILE_LEVEL = (
178
+ process.env.LOG_FILE_LEVEL || DEFAULT_LEVEL
179
+ ).toLowerCase() as LoggerLevel;
180
+
181
+ const DEFAULT_FILE_PATH = process.env.LOG_FILE_PATH;
182
+
183
+ export const logger = winston.createLogger({
184
+ level: DEFAULT_LEVEL,
185
+ transports: [],
35
186
  });
187
+
188
+ export function configureLogger(config: LoggerConfig = {}): winston.Logger {
189
+ const level = config.level ?? DEFAULT_LEVEL;
190
+ const consoleLevel = config.consoleLevel ?? DEFAULT_CONSOLE_LEVEL;
191
+ const fileLevel = config.fileLevel ?? DEFAULT_FILE_LEVEL;
192
+ const filePath = config.filePath ?? DEFAULT_FILE_PATH;
193
+ const enableConsole = config.enableConsole ?? true;
194
+ const enableFile = config.enableFile ?? Boolean(filePath);
195
+ const colorizeConsole = config.colorizeConsole ?? true;
196
+ const shortErrorsInConsole = config.shortErrorsInConsole ?? true;
197
+ const emitConfigLog = config.emitConfigLog ?? false;
198
+
199
+ logger.clear();
200
+ logger.level = level;
201
+
202
+ if (enableConsole) {
203
+ logger.add(
204
+ new winston.transports.Console({
205
+ level: consoleLevel,
206
+ format: format.combine(
207
+ colorizeConsole ? format.colorize({ level: true }) : format.uncolorize(),
208
+ format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
209
+ format.errors({ stack: true }),
210
+ format.printf(({ timestamp, level, message, stack, ...meta }) => {
211
+ const baseMessage = stringifyUnknown(message);
212
+ const { tag, body } = extractTagAndMessage(baseMessage);
213
+ const consoleBody = colorizeConsole
214
+ ? colorizeMessageForConsole(body)
215
+ : body;
216
+ let out = `ts="${timestamp}" level=${stringifyUnknown(level)} [${tag}] msg="${escapeMessageValue(consoleBody)}"`;
217
+ if (!shortErrorsInConsole) {
218
+ const derivedStack = getStackFromMeta(stack, meta);
219
+ if (derivedStack) {
220
+ out += ` stack="${escapeValue(derivedStack)}"`;
221
+ }
222
+ }
223
+ return out;
224
+ }),
225
+ ),
226
+ }),
227
+ );
228
+ }
229
+
230
+ if (enableFile && filePath) {
231
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
232
+ logger.add(
233
+ new winston.transports.File({
234
+ filename: filePath,
235
+ level: fileLevel,
236
+ format: format.combine(
237
+ format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
238
+ format.errors({ stack: true }),
239
+ format.printf(({ timestamp, level, message, stack, ...meta }) => {
240
+ const parsedMessage = stringifyUnknown(message);
241
+ const normalizedMessage = stripAnsi(parsedMessage);
242
+ const { tag, body } = extractTagAndMessage(normalizedMessage);
243
+ let out = `ts="${timestamp}" level=${stripAnsi(level)} [${tag}] msg="${escapeMessageValue(body)}"`;
244
+ const derivedStack = getStackFromMeta(stack, meta);
245
+ if (derivedStack) {
246
+ out += ` stack="${escapeValue(stripAnsi(derivedStack))}"`;
247
+ }
248
+ const metaCopy = { ...meta } as Record<string, unknown>;
249
+ delete metaCopy[
250
+ Symbol.for("splat") as unknown as keyof typeof metaCopy
251
+ ];
252
+ if (Object.keys(metaCopy).length > 0) {
253
+ out += ` meta=${escapeValue(stringifyUnknown(metaCopy))}`;
254
+ }
255
+ return out;
256
+ }),
257
+ ),
258
+ }),
259
+ );
260
+ }
261
+
262
+ if (emitConfigLog) {
263
+ logger.info(
264
+ `[Logger] configured level=${level} console=${enableConsole ? consoleLevel : "off"} file=${enableFile ? fileLevel : "off"}${filePath ? ` path=${filePath}` : ""}`,
265
+ );
266
+ }
267
+ return logger;
268
+ }
269
+
270
+ configureLogger();