@strkfarm/sdk 1.0.38 → 1.0.40

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/src/global.ts CHANGED
@@ -1,39 +1,7 @@
1
1
  import axios from 'axios';
2
2
  import { TokenInfo } from './interfaces';
3
3
  import { ContractAddr } from './dataTypes';
4
-
5
- const colors = {
6
- error: 'red',
7
- warn: 'yellow',
8
- info: 'blue',
9
- verbose: 'white',
10
- debug: 'white',
11
- }
12
-
13
- // Add custom colors to Winston
14
- // winston.addColors(colors);
15
-
16
- // export const logger = createLogger({
17
- // level: 'verbose', // Set the minimum logging level
18
- // format: format.combine(
19
- // format.colorize({ all: true }), // Apply custom colors
20
- // format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // Add timestamp to log messages
21
- // format.printf(({ timestamp, level, message }) => {
22
- // return `${timestamp} ${level}: ${message}`;
23
- // })
24
- // ),
25
- // transports: [
26
- // // new transports.Console() // Output logs to the console
27
- // ]
28
- // });
29
-
30
-
31
- export const logger = {
32
- ...console,
33
- verbose(message: string) {
34
- console.log(`[VERBOSE] ${message}`);
35
- }
36
- };
4
+ import { logger } from '@/utils/logger';
37
5
 
38
6
 
39
7
  export class FatalError extends Error {
@@ -70,6 +70,7 @@ export interface IStrategyMetadata<T> {
70
70
  name: string;
71
71
  description: string | React.ReactNode;
72
72
  address: ContractAddr;
73
+ launchBlock: number;
73
74
  type: "ERC4626" | "ERC721" | "Other";
74
75
  depositTokens: TokenInfo[];
75
76
  protocols: IProtocol[];
@@ -1,10 +1,9 @@
1
1
  import { IConfig } from "@/interfaces/common";
2
2
  import { TokenInfo } from "./common";
3
3
  import { ContractAddr } from "@/dataTypes/address";
4
- import { loggers } from "winston";
5
- import { logger } from "@/global";
6
4
  import { log } from "console";
7
5
  import { Web3Number } from "@/dataTypes";
6
+ import { logger } from "@/utils/logger";
8
7
 
9
8
  export interface ILendingMetadata {
10
9
  name: string;
@@ -3,7 +3,7 @@ import { uint256 } from "starknet";
3
3
  import { Call, Uint256 } from "starknet";
4
4
  import { fetchBuildExecuteTransaction, fetchQuotes, Quote } from "@avnu/avnu-sdk";
5
5
  import { assert } from "../utils";
6
- import { logger } from "@/global";
6
+ import { logger } from "@/utils/logger";
7
7
 
8
8
  export interface Route {
9
9
  token_from: string,
@@ -20,4 +20,10 @@ export class ERC20 {
20
20
  const balance = await contract.call('balanceOf', [address.toString()]);
21
21
  return Web3Number.fromWei(balance.toString(), tokenDecimals);
22
22
  }
23
+
24
+ async allowance(token: string | ContractAddr, owner: string | ContractAddr, spender: string | ContractAddr, tokenDecimals: number) {
25
+ const contract = this.contract(token);
26
+ const allowance = await contract.call('allowance', [owner.toString(), spender.toString()]);
27
+ return Web3Number.fromWei(allowance.toString(), tokenDecimals);
28
+ }
23
29
  }
@@ -1,5 +1,5 @@
1
1
  import { ContractAddr, Web3Number } from "@/dataTypes";
2
- import { logger } from "@/global";
2
+ import { logger } from "@/utils/logger";
3
3
  import { IConfig } from "@/interfaces";
4
4
  import { assert } from "@/utils";
5
5
  import { Contract, num } from "starknet";
@@ -1,6 +1,6 @@
1
1
  import { Contract, RpcProvider } from "starknet";
2
2
  import PragmaAbi from '@/data/pragma.abi.json';
3
- import { logger } from "@/global";
3
+ import { logger } from "@/utils/logger";
4
4
 
5
5
  export class Pragma {
6
6
  contractAddr = '0x023fb3afbff2c0e3399f896dcf7400acf1a161941cfb386e34a123f228c62832';
@@ -1,8 +1,8 @@
1
- import { logger } from "@/global";
2
- import { PriceInfo } from "./pricer";
1
+ import { PriceInfo } from "./pricer";
3
2
  import axios from "axios";
4
3
  import { IConfig, TokenInfo } from "@/interfaces";
5
4
  import { PricerBase } from "./pricerBase";
5
+ import { logger } from "@/utils/logger";
6
6
 
7
7
  export class PricerFromApi extends PricerBase {
8
8
  constructor(config: IConfig, tokens: TokenInfo[]) {
@@ -15,7 +15,7 @@ export class PricerFromApi extends PricerBase {
15
15
  } catch (e: any) {
16
16
  logger.warn('getPriceFromMyAPI error', JSON.stringify(e.message || e));
17
17
  }
18
- logger.log('getPrice coinbase', tokenSymbol);
18
+ logger.info('getPrice coinbase', tokenSymbol);
19
19
  let retry = 0;
20
20
  const MAX_RETRIES = 5;
21
21
  for (retry = 1; retry < MAX_RETRIES + 1; retry++) {
@@ -1,9 +1,10 @@
1
1
  import axios from "axios";
2
- import { FatalError, Global, logger } from "@/global";
2
+ import { FatalError, Global } from "@/global";
3
3
  import { TokenInfo } from "@/interfaces/common";
4
4
  import { IConfig } from "@/interfaces/common";
5
5
  import { Web3Number } from "@/dataTypes";
6
6
  import { PricerBase } from "./pricerBase";
7
+ import { logger } from "@/utils/logger";
7
8
 
8
9
  export interface PriceInfo {
9
10
  price: number,
@@ -1,12 +1,13 @@
1
1
  import axios from "axios";
2
2
  import BigNumber from "bignumber.js";
3
3
  import { Web3Number } from "@/dataTypes/bignumber.browser";
4
- import { FatalError, Global, logger } from "@/global";
4
+ import { FatalError, Global } from "@/global";
5
5
  import { TokenInfo } from "@/interfaces";
6
6
  import { ILending, ILendingPosition, LendingToken, MarginType } from "@/interfaces/lending";
7
7
  import { ContractAddr } from "@/dataTypes/address";
8
8
  import { IConfig } from "@/interfaces";
9
9
  import { Pricer } from "./pricer";
10
+ import { logger } from "@/utils/logger";
10
11
 
11
12
  export class ZkLend extends ILending implements ILending {
12
13
  readonly pricer: Pricer;
@@ -1,8 +1,9 @@
1
- import { FatalError, Global, logger } from '@/global';
1
+ import { FatalError, Global } from '@/global';
2
2
  import { IConfig, TokenInfo } from '@/interfaces';
3
3
  import { PriceInfo, Pricer } from '@/modules/pricer';
4
4
  import { createClient } from 'redis';
5
5
  import type { RedisClientType } from 'redis'
6
+ import { logger } from "@/utils/logger";
6
7
 
7
8
  export class PricerRedis extends Pricer {
8
9
  private redisClient: RedisClientType | null = null;
@@ -1,5 +1,5 @@
1
- import { logger } from "@/global";
2
1
  import TelegramBot from "node-telegram-bot-api";
2
+ import { logger } from "@/utils/logger";
3
3
 
4
4
  export class TelegramNotif {
5
5
  private subscribers: string[] = [
@@ -24,13 +24,14 @@ import CLVaultAbi from "@/data/cl-vault.abi.json";
24
24
  import EkuboPositionsAbi from "@/data/ekubo-positions.abi.json";
25
25
  import EkuboMathAbi from "@/data/ekubo-math.abi.json";
26
26
  import ERC4626Abi from "@/data/erc4626.abi.json";
27
- import { Global, logger } from "@/global";
27
+ import { Global } from "@/global";
28
28
  import { AvnuWrapper, ERC20, SwapInfo } from "@/modules";
29
29
  import { BaseStrategy } from "./base-strategy";
30
30
  import { DualActionAmount } from "./base-strategy";
31
31
  import { DualTokenInfo } from "./base-strategy";
32
32
  import { log } from "winston";
33
33
  import { EkuboHarvests } from "@/modules/harvests";
34
+ import { logger } from "@/utils/logger";
34
35
 
35
36
  export interface EkuboPoolKey {
36
37
  token0: ContractAddr;
@@ -58,7 +59,8 @@ export interface CLVaultStrategySettings {
58
59
  upper: number;
59
60
  };
60
61
  // to get true price
61
- lstContract: ContractAddr;
62
+ lstContract?: ContractAddr;
63
+ truePrice?: number; // useful for pools where price is known (e.g. USDC/USDT as 1)
62
64
  feeBps: number;
63
65
  }
64
66
 
@@ -78,7 +80,7 @@ export class EkuboCLVault extends BaseStrategy<
78
80
 
79
81
  readonly ekuboPositionsContract: Contract;
80
82
  readonly ekuboMathContract: Contract;
81
- readonly lstContract: Contract;
83
+ readonly lstContract: Contract | null;
82
84
  poolKey: EkuboPoolKey | undefined;
83
85
  readonly avnu: AvnuWrapper;
84
86
 
@@ -109,11 +111,15 @@ export class EkuboCLVault extends BaseStrategy<
109
111
  this.address.address,
110
112
  this.config.provider
111
113
  );
112
- this.lstContract = new Contract(
113
- ERC4626Abi,
114
- this.metadata.additionalInfo.lstContract.address,
115
- this.config.provider
116
- );
114
+ if (this.metadata.additionalInfo.lstContract) {
115
+ this.lstContract = new Contract(
116
+ ERC4626Abi,
117
+ this.metadata.additionalInfo.lstContract.address,
118
+ this.config.provider
119
+ );
120
+ } else {
121
+ this.lstContract = null;
122
+ }
117
123
 
118
124
  // ekubo positions contract
119
125
  const EKUBO_POSITION =
@@ -291,7 +297,7 @@ export class EkuboCLVault extends BaseStrategy<
291
297
  ? (await this.config.provider.getBlockWithTxs(blockIdentifier))
292
298
  .timestamp
293
299
  : new Date().getTime() / 1000;
294
- const blockBefore = blockNow - sinceBlocks;
300
+ const blockBefore = Math.max(blockNow - sinceBlocks, this.metadata.launchBlock);
295
301
  const adjustedSupplyNow = supplyNow.minus(
296
302
  await this.getHarvestRewardShares(blockBefore, blockNow)
297
303
  );
@@ -307,13 +313,13 @@ export class EkuboCLVault extends BaseStrategy<
307
313
  .plus(tvlNow.amount1);
308
314
  const tvlPerShareNow = tvlInToken0Now
309
315
  .multipliedBy(1e18)
310
- .dividedBy(adjustedSupplyNow);
316
+ .dividedBy(adjustedSupplyNow.toString());
311
317
  const tvlInToken0Bf = tvlBefore.amount0
312
318
  .multipliedBy(priceBefore.price)
313
319
  .plus(tvlBefore.amount1);
314
320
  const tvlPerShareBf = tvlInToken0Bf
315
321
  .multipliedBy(1e18)
316
- .dividedBy(supplyBefore);
322
+ .dividedBy(supplyBefore.toString());
317
323
  const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
318
324
  logger.verbose(`tvlInToken0Now: ${tvlInToken0Now.toString()}`);
319
325
  logger.verbose(`tvlInToken0Bf: ${tvlInToken0Bf.toString()}`);
@@ -362,7 +368,9 @@ export class EkuboCLVault extends BaseStrategy<
362
368
  user: ContractAddr,
363
369
  blockIdentifier: BlockIdentifier = "pending"
364
370
  ): Promise<Web3Number> {
365
- let bal = await this.contract.call("balance_of", [user.address]);
371
+ let bal = await this.contract.call("balance_of", [user.address], {
372
+ blockIdentifier
373
+ });
366
374
  return Web3Number.fromWei(bal.toString(), 18);
367
375
  }
368
376
 
@@ -529,12 +537,18 @@ export class EkuboCLVault extends BaseStrategy<
529
537
  }
530
538
 
531
539
  async truePrice() {
532
- const result: any = await this.lstContract.call("convert_to_assets", [
533
- uint256.bnToUint256(BigInt(1e18).toString()),
534
- ]);
535
- const truePrice =
536
- Number((BigInt(result.toString()) * BigInt(1e9)) / BigInt(1e18)) / 1e9;
537
- return truePrice;
540
+ if (this.metadata.additionalInfo.truePrice) {
541
+ return this.metadata.additionalInfo.truePrice;
542
+ } else if (this.lstContract) {
543
+ const result: any = await this.lstContract.call("convert_to_assets", [
544
+ uint256.bnToUint256(BigInt(1e18).toString()),
545
+ ]);
546
+ const truePrice =
547
+ Number((BigInt(result.toString()) * BigInt(1e9)) / BigInt(1e18)) / 1e9;
548
+ return truePrice;
549
+ }
550
+
551
+ throw new Error("No true price available");
538
552
  }
539
553
 
540
554
  async getCurrentPrice(blockIdentifier: BlockIdentifier = "pending") {
@@ -1294,7 +1308,7 @@ export class EkuboCLVault extends BaseStrategy<
1294
1308
  const harvestEstimateCall = async (swapInfo1: SwapInfo) => {
1295
1309
  const swap1Amount = Web3Number.fromWei(
1296
1310
  uint256.uint256ToBN(swapInfo1.token_from_amount).toString(),
1297
- 18
1311
+ 18, // cause its always STRK?
1298
1312
  );
1299
1313
  const remainingAmount = postFeeAmount.minus(swap1Amount);
1300
1314
  const swapInfo2 = {
@@ -1401,6 +1415,10 @@ const _riskFactor: RiskFactor[] = [
1401
1415
  { type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25 },
1402
1416
  { type: RiskType.IMPERMANENT_LOSS, value: 1, weight: 75 },
1403
1417
  ];
1418
+
1419
+ const _riskFactorStable: RiskFactor[] = [
1420
+ { type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25 },
1421
+ ];
1404
1422
  const AUDIT_URL =
1405
1423
  "https://assets.strkfarm.com/strkfarm/audit_report_vesu_and_ekubo_strats.pdf";
1406
1424
 
@@ -1458,6 +1476,7 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1458
1476
  address: ContractAddr.from(
1459
1477
  "0x01f083b98674bc21effee29ef443a00c7b9a500fd92cf30341a3da12c73f2324"
1460
1478
  ),
1479
+ launchBlock: 1209881,
1461
1480
  type: "Other",
1462
1481
  // must be same order as poolKey token0 and token1
1463
1482
  depositTokens: [
@@ -1495,4 +1514,57 @@ export const EkuboCLVaultStrategies: IStrategyMetadata<CLVaultStrategySettings>[
1495
1514
  },
1496
1515
  ]
1497
1516
  },
1517
+ {
1518
+ name: "Ekubo USDC/USDT",
1519
+ description: (
1520
+ <div>
1521
+ <p>{_description.replace("{{POOL_NAME}}", "USDC/USDT")}</p>
1522
+ <ul
1523
+ style={{
1524
+ marginLeft: "20px",
1525
+ listStyle: "circle",
1526
+ fontSize: "12px",
1527
+ }}
1528
+ >
1529
+ <li style={{ marginTop: "10px" }}>
1530
+ During withdrawal, you may receive either or both tokens depending
1531
+ on market conditions and prevailing prices.
1532
+ </li>
1533
+ </ul>
1534
+ </div>
1535
+ ),
1536
+ address: ContractAddr.from(
1537
+ "0xd647ed735f0db52f2a5502b6e06ed21dc4284a43a36af4b60d3c80fbc56c91"
1538
+ ),
1539
+ launchBlock: 1385576,
1540
+ type: "Other",
1541
+ // must be same order as poolKey token0 and token1
1542
+ depositTokens: [
1543
+ Global.getDefaultTokens().find((t) => t.symbol === "USDC")!,
1544
+ Global.getDefaultTokens().find((t) => t.symbol === "USDT")!,
1545
+ ],
1546
+ protocols: [_protocol],
1547
+ auditUrl: AUDIT_URL,
1548
+ maxTVL: Web3Number.fromWei("0", 6),
1549
+ risk: {
1550
+ riskFactor: _riskFactorStable,
1551
+ netRisk:
1552
+ _riskFactorStable.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1553
+ _riskFactorStable.reduce((acc, curr) => acc + curr.weight, 0),
1554
+ notARisks: getNoRiskTags(_riskFactorStable),
1555
+ },
1556
+ apyMethodology:
1557
+ "APY based on 7-day historical performance, including fees and rewards.",
1558
+ additionalInfo: {
1559
+ newBounds: {
1560
+ lower: -1,
1561
+ upper: 1,
1562
+ },
1563
+ truePrice: 1,
1564
+ feeBps: 1000,
1565
+ },
1566
+ faqs: [
1567
+ ...faqs,
1568
+ ]
1569
+ },
1498
1570
  ];
@@ -13,8 +13,9 @@ import {
13
13
  import { AvnuWrapper, Pricer, SwapInfo } from "@/modules";
14
14
  import { Account, CairoCustomEnum, Contract, num, uint256 } from "starknet";
15
15
  import VesuRebalanceAbi from "@/data/vesu-rebalance.abi.json";
16
- import { Global, logger } from "@/global";
16
+ import { Global } from "@/global";
17
17
  import { assert } from "@/utils";
18
+ import { logger } from "@/utils/logger";
18
19
  import axios from "axios";
19
20
  import { PricerBase } from "@/modules/pricerBase";
20
21
  import {
@@ -954,6 +955,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
954
955
  address: ContractAddr.from(
955
956
  "0x7fb5bcb8525954a60fde4e8fb8220477696ce7117ef264775a1770e23571929"
956
957
  ),
958
+ launchBlock: 0,
957
959
  type: "ERC4626",
958
960
  depositTokens: [
959
961
  Global.getDefaultTokens().find((t) => t.symbol === "STRK")!
@@ -979,6 +981,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
979
981
  address: ContractAddr.from(
980
982
  "0x5eaf5ee75231cecf79921ff8ded4b5ffe96be718bcb3daf206690ad1a9ad0ca"
981
983
  ),
984
+ launchBlock: 0,
982
985
  type: "ERC4626",
983
986
  auditUrl: AUDIT_URL,
984
987
  depositTokens: [
@@ -1004,6 +1007,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
1004
1007
  address: ContractAddr.from(
1005
1008
  "0xa858c97e9454f407d1bd7c57472fc8d8d8449a777c822b41d18e387816f29c"
1006
1009
  ),
1010
+ launchBlock: 0,
1007
1011
  type: "ERC4626",
1008
1012
  auditUrl: AUDIT_URL,
1009
1013
  depositTokens: [
@@ -1029,6 +1033,7 @@ export const VesuRebalanceStrategies: IStrategyMetadata<VesuRebalanceSettings>[]
1029
1033
  address: ContractAddr.from(
1030
1034
  "0x115e94e722cfc4c77a2f15c4aefb0928c1c0029e5a57570df24c650cb7cec2c"
1031
1035
  ),
1036
+ launchBlock: 0,
1032
1037
  type: "ERC4626",
1033
1038
  depositTokens: [
1034
1039
  Global.getDefaultTokens().find((t) => t.symbol === "USDT")!
@@ -1,3 +1,5 @@
1
+ export * from '@/utils/logger';
2
+
1
3
  // Utility type to make all optional properties required
2
4
  export type RequiredFields<T> = {
3
5
  [K in keyof T]-?: T[K]
@@ -0,0 +1,20 @@
1
+
2
+ interface LeveledLogMethod {
3
+ (message: string, ...meta: any[]): void;
4
+ (message: any): void
5
+ }
6
+
7
+ interface MyLogger {
8
+ error: LeveledLogMethod;
9
+ warn: LeveledLogMethod;
10
+ info: LeveledLogMethod;
11
+ verbose: LeveledLogMethod;
12
+ debug: LeveledLogMethod;
13
+ }
14
+
15
+ export const logger: MyLogger = {
16
+ ...console,
17
+ verbose(message: string) {
18
+ console.log(`[VERBOSE] ${message}`);
19
+ }
20
+ };
@@ -0,0 +1,35 @@
1
+ import winston, { format } from "winston";
2
+
3
+ const colors = {
4
+ error: "red",
5
+ warn: "yellow",
6
+ info: "blue",
7
+ verbose: "white",
8
+ debug: "white",
9
+ };
10
+
11
+ // Add custom colors to Winston
12
+ winston.addColors(colors);
13
+
14
+ export const logger = winston.createLogger({
15
+ level: "verbose", // 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
+ }
29
+ return msg;
30
+ })
31
+ ),
32
+ transports: [
33
+ new winston.transports.Console(), // Output logs to the console
34
+ ],
35
+ });
@@ -0,0 +1 @@
1
+ export * from '@/utils/logger.browser';
@@ -3,8 +3,8 @@ import fs, { readFileSync, writeFileSync } from 'fs';
3
3
  import { Account, constants } from 'starknet';
4
4
  import * as crypto from 'crypto';
5
5
  import { PasswordJsonCryptoUtil } from './encrypt';
6
- import { logger } from '..';
7
6
  import { log } from 'winston';
7
+ import { logger } from "@/utils/logger";
8
8
 
9
9
  /**
10
10
  * @description Config to manage storage of files on disk