@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.
- package/dist/cli.js +74 -11
- package/dist/cli.mjs +69 -12
- package/dist/index.browser.global.js +9447 -9894
- package/dist/index.browser.mjs +2582 -0
- package/dist/index.d.ts +305 -75
- package/dist/index.js +2143 -246
- package/dist/index.mjs +2135 -250
- package/package.json +15 -9
- package/src/data/vesu-rebalance.abi.json +1473 -0
- package/src/dataTypes/bignumber.ts +4 -2
- package/src/global.ts +13 -1
- package/src/index.ts +4 -1
- package/src/interfaces/common.ts +47 -0
- package/src/modules/index.ts +2 -1
- package/src/modules/pricer-from-api.ts +61 -0
- package/src/modules/pricer.ts +12 -17
- package/src/modules/pricerBase.ts +15 -0
- package/src/modules/zkLend.ts +1 -0
- package/src/node/pricer-redis.ts +1 -0
- package/src/strategies/index.ts +2 -1
- package/src/strategies/vesu-rebalance.ts +466 -0
- package/src/utils/index.ts +7 -4
|
@@ -25,11 +25,13 @@ export class Web3Number extends BigNumber {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
multipliedBy(value: string | number) {
|
|
28
|
-
|
|
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
|
-
|
|
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
package/src/interfaces/common.ts
CHANGED
|
@@ -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({
|
package/src/modules/index.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/modules/pricer.ts
CHANGED
|
@@ -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
|
-
|
|
6
|
+
import { PricerBase } from "./pricerBase";
|
|
7
7
|
|
|
8
8
|
export interface PriceInfo {
|
|
9
9
|
price: number,
|
|
10
10
|
timestamp: Date
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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(
|
|
84
|
-
Global.assert(this.prices[
|
|
85
|
-
this.assertNotStale(this.prices[
|
|
86
|
-
return this.prices[
|
|
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
|
-
|
|
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(
|
|
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
|
+
}
|
package/src/modules/zkLend.ts
CHANGED
|
@@ -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
|
package/src/node/pricer-redis.ts
CHANGED
package/src/strategies/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './autoCompounderStrk';
|
|
1
|
+
export * from './autoCompounderStrk';
|
|
2
|
+
export * from './vesu-rebalance';
|