@strkfarm/sdk 1.0.15 → 1.0.17

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.
@@ -25,11 +25,13 @@ export class Web3Number extends BigNumber {
25
25
  }
26
26
 
27
27
  multipliedBy(value: string | number) {
28
- return new Web3Number(this.mul(value).toString(), this.decimals);
28
+ let _value = Number(value).toFixed(6);
29
+ return new Web3Number(this.mul(_value).toString(), this.decimals);
29
30
  }
30
31
 
31
32
  dividedBy(value: string | number) {
32
- return new Web3Number(this.div(value).toString(), this.decimals);
33
+ let _value = Number(value).toFixed(6);
34
+ return new Web3Number(this.div(_value).toString(), this.decimals);
33
35
  }
34
36
 
35
37
  plus(value: string | number) {
package/src/global.ts CHANGED
@@ -45,7 +45,14 @@ export class FatalError extends Error {
45
45
  }
46
46
  }
47
47
 
48
- const tokens: TokenInfo[] = [];
48
+ const tokens: TokenInfo[] = [{
49
+ name: 'Starknet',
50
+ symbol: 'STRK',
51
+ logo: 'https://assets.coingecko.com/coins/images/26433/small/starknet.png',
52
+ address: '0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',
53
+ decimals: 18,
54
+ coingeckId: 'starknet'
55
+ }];
49
56
 
50
57
  /** Contains globally useful functions.
51
58
  * - fatalError: Things to do when a fatal error occurs
@@ -64,6 +71,10 @@ export class Global {
64
71
  console.error(err);
65
72
  }
66
73
 
74
+ static getDefaultTokens() {
75
+ return tokens;
76
+ }
77
+
67
78
  static async getTokens(): Promise<TokenInfo[]> {
68
79
  if (tokens.length) return tokens;
69
80
 
@@ -100,6 +111,7 @@ export class Global {
100
111
  symbol: token.symbol,
101
112
  address: token.address,
102
113
  decimals: token.decimals,
114
+ logo: token.logoUri,
103
115
  coingeckId: token.extensions.coingeckoId,
104
116
  });
105
117
  });
package/src/index.ts CHANGED
@@ -6,4 +6,7 @@ export * from './global';
6
6
  export * from './strategies';
7
7
  export * from './notifs';
8
8
  export * from './utils';
9
- export * from './node';
9
+ export * from './node';
10
+
11
+ export * from './utils/store';
12
+ export * from './utils/encrypt';
@@ -1,10 +1,27 @@
1
+ import { ContractAddr, Web3Number } from "@/dataTypes"
1
2
  import { BlockIdentifier, RpcProvider } from "starknet"
2
3
 
4
+ export enum RiskType {
5
+ MARKET_RISK = 'MARKET_RISK',
6
+ IMPERMANENT_LOSS = 'IMPERMANENT_LOSS',
7
+ LIQUIDITY_RISK = 'LIQUIDITY_RISK',
8
+ SMART_CONTRACT_RISK = 'SMART_CONTRACT_RISK',
9
+ TECHNICAL_RISK = 'TECHNICAL_RISK',
10
+ COUNTERPARTY_RISK = 'COUNTERPARTY_RISK', // e.g. bad debt
11
+ }
12
+
13
+ export interface RiskFactor {
14
+ type: RiskType,
15
+ value: number, // 0 to 5
16
+ weight: number // 0 to 100
17
+ }
18
+
3
19
  export interface TokenInfo {
4
20
  name: string,
5
21
  symbol: string,
6
22
  address: string,
7
23
  decimals: number,
24
+ logo: string,
8
25
  coingeckId?: string,
9
26
  }
10
27
 
@@ -21,6 +38,36 @@ export interface IConfig {
21
38
  heartbeatUrl?: string
22
39
  }
23
40
 
41
+ export interface IProtocol {
42
+ name: string,
43
+ logo: string,
44
+ }
45
+
46
+ /**
47
+ * @property risk.riskFactor.factor - The risk factors that are considered for the strategy.
48
+ * @property risk.riskFactor.factor - The value of the risk factor from 0 to 10, 0 being the lowest and 10 being the highest.
49
+ */
50
+ export interface IStrategyMetadata {
51
+ name: string,
52
+ description: string,
53
+ address: ContractAddr,
54
+ type: 'ERC4626' | 'ERC721' | 'Other',
55
+ depositTokens: TokenInfo[],
56
+ protocols: IProtocol[],
57
+ auditUrl?: string,
58
+ maxTVL: Web3Number,
59
+ risk: {
60
+ riskFactor: RiskFactor[],
61
+ netRisk: number
62
+ }
63
+ }
64
+
65
+ export interface IInvestmentFlow {
66
+ title: string,
67
+ subItems: string[],
68
+ linkedFlows: IInvestmentFlow[],
69
+ }
70
+
24
71
  export function getMainnetConfig(rpcUrl = "https://starknet-mainnet.public.blastapi.io", blockIdentifier: BlockIdentifier = 'pending'): IConfig {
25
72
  return {
26
73
  provider: new RpcProvider({
@@ -1,3 +1,4 @@
1
1
  export * from './pricer';
2
2
  export * from './pragma';
3
- export * from './zkLend';
3
+ export * from './zkLend';
4
+ export * from './pricer-from-api';
@@ -0,0 +1,61 @@
1
+ import { logger } from "@/global";
2
+ import { PriceInfo } from "./pricer";
3
+ import axios from "axios";
4
+ import { IConfig, TokenInfo } from "@/interfaces";
5
+ import { PricerBase } from "./pricerBase";
6
+
7
+ export class PricerFromApi extends PricerBase {
8
+ constructor(config: IConfig, tokens: TokenInfo[]) {
9
+ super(config, tokens);
10
+ }
11
+
12
+ async getPrice(tokenSymbol: string): Promise<PriceInfo> {
13
+ try {
14
+ return await this.getPriceFromMyAPI(tokenSymbol);
15
+ } catch (e) {
16
+ logger.warn('getPriceFromMyAPI error', e);
17
+ }
18
+ logger.log('getPrice coinbase', tokenSymbol);
19
+ let retry = 0;
20
+ const MAX_RETRIES = 5;
21
+ for (retry = 1; retry < MAX_RETRIES + 1; retry++) {
22
+ try {
23
+ const priceInfo = await axios.get(
24
+ `https://api.coinbase.com/v2/prices/${tokenSymbol}-USDT/spot`,
25
+ );
26
+ if (!priceInfo) {
27
+ throw new Error('Failed to fetch price');
28
+ }
29
+ const data = await priceInfo.data;
30
+ const price = Number(data.data.amount);
31
+ return {
32
+ price,
33
+ timestamp: new Date()
34
+ }
35
+ } catch (e) {
36
+ logger.warn('getPrice coinbase error', e, retry);
37
+ await new Promise((resolve) => setTimeout(resolve, retry * 1000));
38
+ }
39
+ }
40
+ throw new Error(`Failed to fetch price for ${tokenSymbol}`);
41
+ }
42
+
43
+ async getPriceFromMyAPI(tokenSymbol: string) {
44
+ logger.verbose(`getPrice from redis: ${tokenSymbol}`);
45
+ const endpoint = 'https://app.strkfarm.com'
46
+ const url = `${endpoint}/api/price/${tokenSymbol}`;
47
+ const priceInfoRes = await fetch(url);
48
+ const priceInfo = await priceInfoRes.json();
49
+ const now = new Date();
50
+ const priceTime = new Date(priceInfo.timestamp);
51
+ if (now.getTime() - priceTime.getTime() > 900000) {
52
+ // 15 mins
53
+ throw new Error('Price is stale');
54
+ }
55
+ const price = Number(priceInfo.price);
56
+ return {
57
+ price,
58
+ timestamp: new Date(priceInfo.timestamp)
59
+ }
60
+ }
61
+ }
@@ -3,15 +3,14 @@ import { FatalError, Global, logger } from "@/global";
3
3
  import { TokenInfo } from "@/interfaces/common";
4
4
  import { IConfig } from "@/interfaces/common";
5
5
  import { Web3Number } from "@/dataTypes";
6
- const CoinMarketCap = require('coinmarketcap-api')
6
+ import { PricerBase } from "./pricerBase";
7
7
 
8
8
  export interface PriceInfo {
9
9
  price: number,
10
10
  timestamp: Date
11
11
  }
12
- export class Pricer {
13
- readonly config: IConfig;
14
- readonly tokens: TokenInfo[] = [];
12
+
13
+ export class Pricer extends PricerBase {
15
14
  protected prices: {
16
15
  [key: string]: PriceInfo
17
16
  } = {}
@@ -26,12 +25,8 @@ export class Pricer {
26
25
  protected PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
27
26
  protected EKUBO_API = 'https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_ADDRESS}}/0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8'; // e.g. ETH/USDC
28
27
 
29
- // backup oracle001
30
- protected client = new CoinMarketCap(process.env.COINMARKETCAP_KEY!);
31
-
32
28
  constructor(config: IConfig, tokens: TokenInfo[]) {
33
- this.config = config;
34
- this.tokens = tokens;
29
+ super(config, tokens);
35
30
  }
36
31
 
37
32
  isReady() {
@@ -80,10 +75,10 @@ export class Pricer {
80
75
  Global.assert(!this.isStale(timestamp, tokenName), `Price of ${tokenName} is stale`);
81
76
 
82
77
  }
83
- async getPrice(tokenName: string) {
84
- Global.assert(this.prices[tokenName], `Price of ${tokenName} not found`);
85
- this.assertNotStale(this.prices[tokenName].timestamp, tokenName);
86
- return this.prices[tokenName];
78
+ async getPrice(tokenSymbol: string) {
79
+ Global.assert(this.prices[tokenSymbol], `Price of ${tokenSymbol} not found`);
80
+ this.assertNotStale(this.prices[tokenSymbol].timestamp, tokenSymbol);
81
+ return this.prices[tokenSymbol];
87
82
  }
88
83
 
89
84
  protected _loadPrices(onUpdate: (tokenSymbol: string) => void = () => {}) {
@@ -180,11 +175,11 @@ export class Pricer {
180
175
  }
181
176
 
182
177
  async _getPriceCoinMarketCap(token: TokenInfo): Promise<number> {
183
- const result = await this.client.getQuotes({symbol: token.symbol});
184
- if (result.data)
185
- return result.data[token.symbol].quote.USD.price as number
178
+ // const result = await this.client.getQuotes({symbol: token.symbol});
179
+ // if (result.data)
180
+ // return result.data[token.symbol].quote.USD.price as number
186
181
 
187
- throw new Error(result);
182
+ throw new Error("Not implemented");
188
183
  }
189
184
 
190
185
  async _getPriceEkubo(token: TokenInfo, amountIn = new Web3Number(1, token.decimals), retry = 0): Promise<number> {
@@ -0,0 +1,15 @@
1
+ import { IConfig, TokenInfo } from "@/interfaces";
2
+ import { PriceInfo } from "./pricer";
3
+
4
+ export abstract class PricerBase {
5
+ readonly config: IConfig;
6
+ readonly tokens: TokenInfo[];
7
+ constructor(config: IConfig, tokens: TokenInfo[]) {
8
+ this.config = config;
9
+ this.tokens = tokens;
10
+ }
11
+
12
+ async getPrice(tokenSymbol: string): Promise<PriceInfo> {
13
+ throw new Error('Method not implemented');
14
+ }
15
+ }
@@ -37,6 +37,7 @@ export class ZkLend extends ILending implements ILending {
37
37
  name: pool.token.name,
38
38
  symbol: pool.token.symbol,
39
39
  address: savedTokenInfo?.address || '',
40
+ logo: '',
40
41
  decimals: pool.token.decimals,
41
42
  borrowFactor: Web3Number.fromWei(pool.borrow_factor.value, pool.borrow_factor.decimals),
42
43
  collareralFactor
@@ -6,6 +6,7 @@ import type { RedisClientType } from 'redis'
6
6
 
7
7
  export class PricerRedis extends Pricer {
8
8
  private redisClient: RedisClientType | null = null;
9
+
9
10
  constructor(config: IConfig, tokens: TokenInfo[]) {
10
11
  super(config, tokens)
11
12
  }
@@ -1 +1,2 @@
1
- export * from './autoCompounderStrk';
1
+ export * from './autoCompounderStrk';
2
+ export * from './vesu-rebalance';