@strkfarm/sdk 1.0.8 → 1.0.10
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 +34 -90
- package/dist/cli.mjs +36 -92
- package/dist/index.browser.global.js +3990 -4029
- package/dist/index.d.ts +29 -27
- package/dist/index.js +122 -160
- package/dist/index.mjs +118 -156
- package/package.json +1 -1
- package/src/global.ts +44 -2
- package/src/interfaces/common.ts +1 -1
- package/src/modules/pricer.ts +31 -6
- package/src/strategies/autoCompounderStrk.ts +4 -3
- package/src/data/tokens.json +0 -72
package/dist/index.mjs
CHANGED
|
@@ -6,83 +6,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
// src/modules/pricer.ts
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
// src/data/tokens.json
|
|
12
|
-
var tokens_default = [
|
|
13
|
-
{
|
|
14
|
-
name: "Ether",
|
|
15
|
-
symbol: "ETH",
|
|
16
|
-
address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
|
|
17
|
-
decimals: 18,
|
|
18
|
-
pricerKey: "ETH-USDT"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: "USD Coin",
|
|
22
|
-
symbol: "USDC",
|
|
23
|
-
address: "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
|
|
24
|
-
decimals: 6,
|
|
25
|
-
pricerKey: "USDC-USDT"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: "Wrapped BTC",
|
|
29
|
-
symbol: "WBTC",
|
|
30
|
-
address: "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
|
|
31
|
-
decimals: 8,
|
|
32
|
-
pricerKey: "WBTC-USDT"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: "Tether USD",
|
|
36
|
-
symbol: "USDT",
|
|
37
|
-
address: "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
|
|
38
|
-
decimals: 6,
|
|
39
|
-
pricerKey: "USDT-USDT"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: "Dai Stablecoin",
|
|
43
|
-
symbol: "DAIv0",
|
|
44
|
-
address: "",
|
|
45
|
-
decimals: 18,
|
|
46
|
-
pricerKey: "DAI-USDT"
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: "Starknet Wrapped Staked Ether",
|
|
50
|
-
symbol: "wstETH",
|
|
51
|
-
address: "0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2",
|
|
52
|
-
decimals: 18,
|
|
53
|
-
pricerKey: "wstETH-USDT"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: "Starknet Token",
|
|
57
|
-
symbol: "STRK",
|
|
58
|
-
address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
|
|
59
|
-
decimals: 18,
|
|
60
|
-
pricerKey: "STRK-USDT"
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: "zkLend Token",
|
|
64
|
-
symbol: "ZEND",
|
|
65
|
-
address: "",
|
|
66
|
-
decimals: 18,
|
|
67
|
-
pricerKey: "ZEND-USDT"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: "Dai Stablecoin",
|
|
71
|
-
symbol: "DAI",
|
|
72
|
-
address: "",
|
|
73
|
-
decimals: 18,
|
|
74
|
-
pricerKey: "DAI-USDT"
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: "Ekubo Protocol",
|
|
78
|
-
symbol: "EKUBO",
|
|
79
|
-
address: "",
|
|
80
|
-
decimals: 18,
|
|
81
|
-
pricerKey: "DAI-USDT"
|
|
82
|
-
}
|
|
83
|
-
];
|
|
9
|
+
import axios2 from "axios";
|
|
84
10
|
|
|
85
11
|
// src/global.ts
|
|
12
|
+
import axios from "axios";
|
|
86
13
|
var logger = {
|
|
87
14
|
...console,
|
|
88
15
|
verbose(message) {
|
|
@@ -98,6 +25,7 @@ var FatalError = class extends Error {
|
|
|
98
25
|
this.name = "FatalError";
|
|
99
26
|
}
|
|
100
27
|
};
|
|
28
|
+
var tokens = [];
|
|
101
29
|
var Global = class {
|
|
102
30
|
static fatalError(message, err) {
|
|
103
31
|
logger.error(message);
|
|
@@ -111,7 +39,23 @@ var Global = class {
|
|
|
111
39
|
console.error(err);
|
|
112
40
|
}
|
|
113
41
|
static async getTokens() {
|
|
114
|
-
return
|
|
42
|
+
if (tokens.length) return tokens;
|
|
43
|
+
const data = await axios.get("https://starknet.api.avnu.fi/v1/starknet/tokens");
|
|
44
|
+
const tokensData = data.data.content;
|
|
45
|
+
tokensData.forEach((token) => {
|
|
46
|
+
if (!token.tags.includes("AVNU") || !token.tags.includes("Verified")) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
tokens.push({
|
|
50
|
+
name: token.name,
|
|
51
|
+
symbol: token.symbol,
|
|
52
|
+
address: token.address,
|
|
53
|
+
decimals: token.decimals,
|
|
54
|
+
coingeckId: token.extensions.coingeckoId
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
console.log(tokens);
|
|
58
|
+
return tokens;
|
|
115
59
|
}
|
|
116
60
|
static assert(condition, message) {
|
|
117
61
|
if (!condition) {
|
|
@@ -120,20 +64,86 @@ var Global = class {
|
|
|
120
64
|
}
|
|
121
65
|
};
|
|
122
66
|
|
|
67
|
+
// src/dataTypes/bignumber.ts
|
|
68
|
+
import BigNumber from "bignumber.js";
|
|
69
|
+
var Web3Number = class _Web3Number extends BigNumber {
|
|
70
|
+
constructor(value, decimals) {
|
|
71
|
+
super(value);
|
|
72
|
+
this.decimals = decimals;
|
|
73
|
+
}
|
|
74
|
+
static fromWei(weiNumber, decimals) {
|
|
75
|
+
const bn = new _Web3Number(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
76
|
+
return new _Web3Number(bn.toString(), decimals);
|
|
77
|
+
}
|
|
78
|
+
toWei() {
|
|
79
|
+
return this.mul(10 ** this.decimals).toFixed(0);
|
|
80
|
+
}
|
|
81
|
+
multipliedBy(value) {
|
|
82
|
+
return new _Web3Number(this.mul(value).toString(), this.decimals);
|
|
83
|
+
}
|
|
84
|
+
dividedBy(value) {
|
|
85
|
+
return new _Web3Number(this.div(value).toString(), this.decimals);
|
|
86
|
+
}
|
|
87
|
+
plus(value) {
|
|
88
|
+
return new _Web3Number(this.add(value).toString(), this.decimals);
|
|
89
|
+
}
|
|
90
|
+
minus(n, base) {
|
|
91
|
+
return new _Web3Number(super.minus(n, base).toString(), this.decimals);
|
|
92
|
+
}
|
|
93
|
+
toString(base) {
|
|
94
|
+
return super.toString(base);
|
|
95
|
+
}
|
|
96
|
+
// [customInspectSymbol](depth: any, inspectOptions: any, inspect: any) {
|
|
97
|
+
// return this.toString();
|
|
98
|
+
// }
|
|
99
|
+
};
|
|
100
|
+
BigNumber.config({ DECIMAL_PLACES: 18 });
|
|
101
|
+
Web3Number.config({ DECIMAL_PLACES: 18 });
|
|
102
|
+
|
|
103
|
+
// src/dataTypes/address.ts
|
|
104
|
+
import { num } from "starknet";
|
|
105
|
+
var ContractAddr = class _ContractAddr {
|
|
106
|
+
constructor(address) {
|
|
107
|
+
this.address = _ContractAddr.standardise(address);
|
|
108
|
+
}
|
|
109
|
+
static from(address) {
|
|
110
|
+
return new _ContractAddr(address);
|
|
111
|
+
}
|
|
112
|
+
eq(other) {
|
|
113
|
+
return this.address === other.address;
|
|
114
|
+
}
|
|
115
|
+
eqString(other) {
|
|
116
|
+
return this.address === _ContractAddr.standardise(other);
|
|
117
|
+
}
|
|
118
|
+
static standardise(address) {
|
|
119
|
+
let _a = address;
|
|
120
|
+
if (!address) {
|
|
121
|
+
_a = "0";
|
|
122
|
+
}
|
|
123
|
+
const a = num.getHexString(num.getDecimalString(_a.toString()));
|
|
124
|
+
return a;
|
|
125
|
+
}
|
|
126
|
+
static eqString(a, b) {
|
|
127
|
+
return _ContractAddr.standardise(a) === _ContractAddr.standardise(b);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
123
131
|
// src/modules/pricer.ts
|
|
124
132
|
var CoinMarketCap = __require("coinmarketcap-api");
|
|
125
133
|
var Pricer = class {
|
|
126
|
-
constructor(config,
|
|
134
|
+
constructor(config, tokens2) {
|
|
127
135
|
this.tokens = [];
|
|
128
136
|
this.prices = {};
|
|
129
137
|
/**
|
|
130
138
|
* TOKENA and TOKENB are the two token names to get price of TokenA in terms of TokenB
|
|
131
139
|
*/
|
|
132
140
|
this.PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
|
|
133
|
-
|
|
141
|
+
this.EKUBO_API = "https://mainnet-api.ekubo.org/quote/{{AMOUNT}}/{{TOKEN_SYMBOL}}/USDC";
|
|
142
|
+
// e.g. ETH/USDC
|
|
143
|
+
// backup oracle001
|
|
134
144
|
this.client = new CoinMarketCap(process.env.COINMARKETCAP_KEY);
|
|
135
145
|
this.config = config;
|
|
136
|
-
this.tokens =
|
|
146
|
+
this.tokens = tokens2;
|
|
137
147
|
}
|
|
138
148
|
isReady() {
|
|
139
149
|
const allPricesExist = Object.keys(this.prices).length === this.tokens.length;
|
|
@@ -217,7 +227,7 @@ var Pricer = class {
|
|
|
217
227
|
});
|
|
218
228
|
if (this.isReady() && this.config.heartbeatUrl) {
|
|
219
229
|
console.log(`sending beat`);
|
|
220
|
-
|
|
230
|
+
axios2.get(this.config.heartbeatUrl).catch((err) => {
|
|
221
231
|
console.error("Pricer: Heartbeat err", err);
|
|
222
232
|
});
|
|
223
233
|
}
|
|
@@ -231,14 +241,15 @@ var Pricer = class {
|
|
|
231
241
|
return await this._getPriceCoinMarketCap(token);
|
|
232
242
|
} catch (error) {
|
|
233
243
|
}
|
|
244
|
+
try {
|
|
245
|
+
return await this._getPriceEkubo(token);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
}
|
|
234
248
|
throw new FatalError(`Price not found for ${token.name}`);
|
|
235
249
|
}
|
|
236
250
|
async _getPriceCoinbase(token) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
const url = this.PRICE_API.replace("{{PRICER_KEY}}", token.pricerKey);
|
|
241
|
-
const result = await axios.get(url);
|
|
251
|
+
const url = this.PRICE_API.replace("{{PRICER_KEY}}", `${token.symbol}-USD`);
|
|
252
|
+
const result = await axios2.get(url);
|
|
242
253
|
const data = result.data;
|
|
243
254
|
return Number(data.data.amount);
|
|
244
255
|
}
|
|
@@ -246,6 +257,20 @@ var Pricer = class {
|
|
|
246
257
|
const result = await this.client.getQuotes({ symbol: token.symbol });
|
|
247
258
|
return result.data[token.symbol].quote.USD.price;
|
|
248
259
|
}
|
|
260
|
+
async _getPriceEkubo(token, amountIn = new Web3Number(1, token.decimals), retry = 0) {
|
|
261
|
+
const url = this.EKUBO_API.replace("{{TOKEN_SYMBOL}}", token.symbol).replace("{{AMOUNT}}", amountIn.toWei());
|
|
262
|
+
const result = await axios2.get(url);
|
|
263
|
+
const data = result.data;
|
|
264
|
+
const outputUSDC = Number(Web3Number.fromWei(data.total, 6).toFixed(6));
|
|
265
|
+
logger.verbose(`Ekubo: ${token.symbol} -> USDC: ${outputUSDC}, retry: ${retry}`);
|
|
266
|
+
if (outputUSDC === 0 && retry < 3) {
|
|
267
|
+
const amountIn2 = new Web3Number(100, token.decimals);
|
|
268
|
+
return await this._getPriceEkubo(token, amountIn2, retry + 1);
|
|
269
|
+
}
|
|
270
|
+
const usdcPrice = (await this.getPrice("USDC")).price;
|
|
271
|
+
logger.verbose(`USDC Price: ${usdcPrice}`);
|
|
272
|
+
return outputUSDC * usdcPrice;
|
|
273
|
+
}
|
|
249
274
|
};
|
|
250
275
|
|
|
251
276
|
// src/modules/pragma.ts
|
|
@@ -367,43 +392,7 @@ var Pragma = class {
|
|
|
367
392
|
};
|
|
368
393
|
|
|
369
394
|
// src/modules/zkLend.ts
|
|
370
|
-
import
|
|
371
|
-
|
|
372
|
-
// src/dataTypes/bignumber.ts
|
|
373
|
-
import BigNumber from "bignumber.js";
|
|
374
|
-
var Web3Number = class _Web3Number extends BigNumber {
|
|
375
|
-
constructor(value, decimals) {
|
|
376
|
-
super(value);
|
|
377
|
-
this.decimals = decimals;
|
|
378
|
-
}
|
|
379
|
-
static fromWei(weiNumber, decimals) {
|
|
380
|
-
const bn = new _Web3Number(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
381
|
-
return new _Web3Number(bn.toString(), decimals);
|
|
382
|
-
}
|
|
383
|
-
toWei() {
|
|
384
|
-
return this.mul(10 ** this.decimals).toFixed(0);
|
|
385
|
-
}
|
|
386
|
-
multipliedBy(value) {
|
|
387
|
-
return new _Web3Number(this.mul(value).toString(), this.decimals);
|
|
388
|
-
}
|
|
389
|
-
dividedBy(value) {
|
|
390
|
-
return new _Web3Number(this.div(value).toString(), this.decimals);
|
|
391
|
-
}
|
|
392
|
-
plus(value) {
|
|
393
|
-
return new _Web3Number(this.add(value).toString(), this.decimals);
|
|
394
|
-
}
|
|
395
|
-
minus(n, base) {
|
|
396
|
-
return new _Web3Number(super.minus(n, base).toString(), this.decimals);
|
|
397
|
-
}
|
|
398
|
-
toString(base) {
|
|
399
|
-
return super.toString(base);
|
|
400
|
-
}
|
|
401
|
-
// [customInspectSymbol](depth: any, inspectOptions: any, inspect: any) {
|
|
402
|
-
// return this.toString();
|
|
403
|
-
// }
|
|
404
|
-
};
|
|
405
|
-
BigNumber.config({ DECIMAL_PLACES: 18 });
|
|
406
|
-
Web3Number.config({ DECIMAL_PLACES: 18 });
|
|
395
|
+
import axios3 from "axios";
|
|
407
396
|
|
|
408
397
|
// src/interfaces/lending.ts
|
|
409
398
|
var MarginType = /* @__PURE__ */ ((MarginType2) => {
|
|
@@ -447,7 +436,7 @@ var _ZkLend = class _ZkLend extends ILending {
|
|
|
447
436
|
async init() {
|
|
448
437
|
try {
|
|
449
438
|
logger.verbose(`Initialising ${this.metadata.name}`);
|
|
450
|
-
const result = await
|
|
439
|
+
const result = await axios3.get(_ZkLend.POOLS_URL);
|
|
451
440
|
const data = result.data;
|
|
452
441
|
const savedTokens = await Global.getTokens();
|
|
453
442
|
data.forEach((pool) => {
|
|
@@ -537,7 +526,7 @@ var _ZkLend = class _ZkLend extends ILending {
|
|
|
537
526
|
*/
|
|
538
527
|
async getPositions(user) {
|
|
539
528
|
const url = this.POSITION_URL.replace("{{USER_ADDR}}", user.address);
|
|
540
|
-
const result = await
|
|
529
|
+
const result = await axios3.get(url);
|
|
541
530
|
const data = result.data;
|
|
542
531
|
const lendingPosition = [];
|
|
543
532
|
logger.verbose(`${this.metadata.name}:: Positions: ${JSON.stringify(data)}`);
|
|
@@ -606,34 +595,6 @@ var Initializable = class {
|
|
|
606
595
|
}
|
|
607
596
|
};
|
|
608
597
|
|
|
609
|
-
// src/dataTypes/address.ts
|
|
610
|
-
import { num } from "starknet";
|
|
611
|
-
var ContractAddr = class _ContractAddr {
|
|
612
|
-
constructor(address) {
|
|
613
|
-
this.address = _ContractAddr.standardise(address);
|
|
614
|
-
}
|
|
615
|
-
static from(address) {
|
|
616
|
-
return new _ContractAddr(address);
|
|
617
|
-
}
|
|
618
|
-
eq(other) {
|
|
619
|
-
return this.address === other.address;
|
|
620
|
-
}
|
|
621
|
-
eqString(other) {
|
|
622
|
-
return this.address === _ContractAddr.standardise(other);
|
|
623
|
-
}
|
|
624
|
-
static standardise(address) {
|
|
625
|
-
let _a = address;
|
|
626
|
-
if (!address) {
|
|
627
|
-
_a = "0";
|
|
628
|
-
}
|
|
629
|
-
const a = num.getHexString(num.getDecimalString(_a.toString()));
|
|
630
|
-
return a;
|
|
631
|
-
}
|
|
632
|
-
static eqString(a, b) {
|
|
633
|
-
return _ContractAddr.standardise(a) === _ContractAddr.standardise(b);
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
|
|
637
598
|
// src/strategies/autoCompounderStrk.ts
|
|
638
599
|
import { Contract as Contract2, uint256 } from "starknet";
|
|
639
600
|
var AutoCompounderSTRK = class {
|
|
@@ -656,8 +617,9 @@ var AutoCompounderSTRK = class {
|
|
|
656
617
|
this.init();
|
|
657
618
|
}
|
|
658
619
|
async init() {
|
|
659
|
-
const
|
|
660
|
-
|
|
620
|
+
const provider = this.config.provider;
|
|
621
|
+
const cls = await provider.getClassAt(this.addr.address);
|
|
622
|
+
this.contract = new Contract2(cls.abi, this.addr.address, provider);
|
|
661
623
|
this.initialized = true;
|
|
662
624
|
}
|
|
663
625
|
async waitForInitilisation() {
|
|
@@ -900,8 +862,8 @@ var Store = class _Store {
|
|
|
900
862
|
// src/node/pricer-redis.ts
|
|
901
863
|
import { createClient } from "redis";
|
|
902
864
|
var PricerRedis = class extends Pricer {
|
|
903
|
-
constructor(config,
|
|
904
|
-
super(config,
|
|
865
|
+
constructor(config, tokens2) {
|
|
866
|
+
super(config, tokens2);
|
|
905
867
|
this.redisClient = null;
|
|
906
868
|
}
|
|
907
869
|
/** Reads prices from Pricer._loadPrices and uses a callback to set prices in redis */
|
package/package.json
CHANGED
package/src/global.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
1
2
|
import { TokenInfo } from './interfaces';
|
|
2
|
-
import TOKENS from '@/data/tokens.json';
|
|
3
3
|
|
|
4
4
|
const colors = {
|
|
5
5
|
error: 'red',
|
|
@@ -44,6 +44,9 @@ export class FatalError extends Error {
|
|
|
44
44
|
this.name = "FatalError";
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
const tokens: TokenInfo[] = [];
|
|
49
|
+
|
|
47
50
|
/** Contains globally useful functions.
|
|
48
51
|
* - fatalError: Things to do when a fatal error occurs
|
|
49
52
|
*/
|
|
@@ -62,7 +65,46 @@ export class Global {
|
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
static async getTokens(): Promise<TokenInfo[]> {
|
|
65
|
-
return
|
|
68
|
+
if (tokens.length) return tokens;
|
|
69
|
+
|
|
70
|
+
// fetch from avnu API
|
|
71
|
+
const data = await axios.get('https://starknet.api.avnu.fi/v1/starknet/tokens');
|
|
72
|
+
const tokensData = data.data.content;
|
|
73
|
+
|
|
74
|
+
// Array of the following is returned
|
|
75
|
+
// {
|
|
76
|
+
// "name": "USD Coin",
|
|
77
|
+
// "address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
|
|
78
|
+
// "symbol": "USDC",
|
|
79
|
+
// "decimals": 6,
|
|
80
|
+
// "logoUri": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
|
|
81
|
+
// "lastDailyVolumeUsd": 2964287916.82621,
|
|
82
|
+
// "extensions": {
|
|
83
|
+
// "coingeckoId": "usd-coin"
|
|
84
|
+
// },
|
|
85
|
+
// "tags": [
|
|
86
|
+
// "AVNU",
|
|
87
|
+
// "Verified"
|
|
88
|
+
// ]
|
|
89
|
+
// }
|
|
90
|
+
|
|
91
|
+
tokensData.forEach((token: any) => {
|
|
92
|
+
// if tags do not contain Avnu and verified, ignore
|
|
93
|
+
// This would exclude meme coins for now
|
|
94
|
+
if (!token.tags.includes('AVNU') || !token.tags.includes('Verified')) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
tokens.push({
|
|
99
|
+
name: token.name,
|
|
100
|
+
symbol: token.symbol,
|
|
101
|
+
address: token.address,
|
|
102
|
+
decimals: token.decimals,
|
|
103
|
+
coingeckId: token.extensions.coingeckoId,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
console.log(tokens);
|
|
107
|
+
return tokens;
|
|
66
108
|
}
|
|
67
109
|
|
|
68
110
|
static assert(condition: any, message: string) {
|
package/src/interfaces/common.ts
CHANGED
package/src/modules/pricer.ts
CHANGED
|
@@ -2,6 +2,7 @@ import axios from "axios";
|
|
|
2
2
|
import { FatalError, Global, logger } from "@/global";
|
|
3
3
|
import { TokenInfo } from "@/interfaces/common";
|
|
4
4
|
import { IConfig } from "@/interfaces/common";
|
|
5
|
+
import { Web3Number } from "@/dataTypes";
|
|
5
6
|
const CoinMarketCap = require('coinmarketcap-api')
|
|
6
7
|
|
|
7
8
|
export interface PriceInfo {
|
|
@@ -19,8 +20,9 @@ export class Pricer {
|
|
|
19
20
|
* TOKENA and TOKENB are the two token names to get price of TokenA in terms of TokenB
|
|
20
21
|
*/
|
|
21
22
|
protected PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
protected EKUBO_API = 'https://mainnet-api.ekubo.org/quote/{{AMOUNT}}/{{TOKEN_SYMBOL}}/USDC'; // e.g. ETH/USDC
|
|
24
|
+
|
|
25
|
+
// backup oracle001
|
|
24
26
|
protected client = new CoinMarketCap(process.env.COINMARKETCAP_KEY!);
|
|
25
27
|
|
|
26
28
|
constructor(config: IConfig, tokens: TokenInfo[]) {
|
|
@@ -136,14 +138,17 @@ export class Pricer {
|
|
|
136
138
|
// do nothing, try next
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
try {
|
|
142
|
+
return await this._getPriceEkubo(token);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
// do nothing, try next
|
|
145
|
+
}
|
|
146
|
+
|
|
139
147
|
throw new FatalError(`Price not found for ${token.name}`);
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
async _getPriceCoinbase(token: TokenInfo) {
|
|
143
|
-
|
|
144
|
-
throw new FatalError(`Pricer key not found for ${token.name}`);
|
|
145
|
-
}
|
|
146
|
-
const url = this.PRICE_API.replace("{{PRICER_KEY}}", token.pricerKey);
|
|
151
|
+
const url = this.PRICE_API.replace("{{PRICER_KEY}}", `${token.symbol}-USD`);
|
|
147
152
|
const result = await axios.get(url);
|
|
148
153
|
const data: any = result.data;
|
|
149
154
|
return Number(data.data.amount);
|
|
@@ -153,4 +158,24 @@ export class Pricer {
|
|
|
153
158
|
const result = await this.client.getQuotes({symbol: token.symbol});
|
|
154
159
|
return result.data[token.symbol].quote.USD.price as number
|
|
155
160
|
}
|
|
161
|
+
|
|
162
|
+
async _getPriceEkubo(token: TokenInfo, amountIn = new Web3Number(1, token.decimals), retry = 0): Promise<number> {
|
|
163
|
+
const url = this.EKUBO_API.replace("{{TOKEN_SYMBOL}}", token.symbol).replace("{{AMOUNT}}", amountIn.toWei());
|
|
164
|
+
const result = await axios.get(url);
|
|
165
|
+
const data: any = result.data;
|
|
166
|
+
const outputUSDC = Number(Web3Number.fromWei(data.total, 6).toFixed(6));
|
|
167
|
+
logger.verbose(`Ekubo: ${token.symbol} -> USDC: ${outputUSDC}, retry: ${retry}`);
|
|
168
|
+
if (outputUSDC === 0 && retry < 3) {
|
|
169
|
+
// try again with a higher amount
|
|
170
|
+
const amountIn = new Web3Number(100, token.decimals); // 100 unit of token
|
|
171
|
+
return await this._getPriceEkubo(token, amountIn, retry + 1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// if usdc depegs, it will not longer be 1 USD
|
|
175
|
+
// so we need to get the price of USDC in USD
|
|
176
|
+
// and then convert the outputUSDC to USD
|
|
177
|
+
const usdcPrice = (await this.getPrice('USDC')).price;
|
|
178
|
+
logger.verbose(`USDC Price: ${usdcPrice}`);
|
|
179
|
+
return outputUSDC * usdcPrice;
|
|
180
|
+
}
|
|
156
181
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
2
|
import { IConfig } from "@/interfaces";
|
|
3
|
-
import { Contract, uint256 } from "starknet";
|
|
3
|
+
import { Contract, RpcProvider, uint256 } from "starknet";
|
|
4
4
|
import { Pricer } from "@/modules/pricer";
|
|
5
5
|
|
|
6
6
|
export class AutoCompounderSTRK {
|
|
@@ -29,8 +29,9 @@ export class AutoCompounderSTRK {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async init() {
|
|
32
|
-
const
|
|
33
|
-
|
|
32
|
+
const provider: RpcProvider = this.config.provider;
|
|
33
|
+
const cls = await provider.getClassAt(this.addr.address);
|
|
34
|
+
this.contract = new Contract(cls.abi, this.addr.address, provider);
|
|
34
35
|
this.initialized = true;
|
|
35
36
|
}
|
|
36
37
|
|
package/src/data/tokens.json
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"name": "Ether",
|
|
4
|
-
"symbol": "ETH",
|
|
5
|
-
"address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
|
|
6
|
-
"decimals": 18,
|
|
7
|
-
"pricerKey": "ETH-USDT"
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
"name": "USD Coin",
|
|
11
|
-
"symbol": "USDC",
|
|
12
|
-
"address": "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
|
|
13
|
-
"decimals": 6,
|
|
14
|
-
"pricerKey": "USDC-USDT"
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"name": "Wrapped BTC",
|
|
18
|
-
"symbol": "WBTC",
|
|
19
|
-
"address": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
|
|
20
|
-
"decimals": 8,
|
|
21
|
-
"pricerKey": "WBTC-USDT"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"name": "Tether USD",
|
|
25
|
-
"symbol": "USDT",
|
|
26
|
-
"address": "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
|
|
27
|
-
"decimals": 6,
|
|
28
|
-
"pricerKey": "USDT-USDT"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"name": "Dai Stablecoin",
|
|
32
|
-
"symbol": "DAIv0",
|
|
33
|
-
"address": "",
|
|
34
|
-
"decimals": 18,
|
|
35
|
-
"pricerKey": "DAI-USDT"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"name": "Starknet Wrapped Staked Ether",
|
|
39
|
-
"symbol": "wstETH",
|
|
40
|
-
"address": "0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2",
|
|
41
|
-
"decimals": 18,
|
|
42
|
-
"pricerKey": "wstETH-USDT"
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"name": "Starknet Token",
|
|
46
|
-
"symbol": "STRK",
|
|
47
|
-
"address": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
|
|
48
|
-
"decimals": 18,
|
|
49
|
-
"pricerKey": "STRK-USDT"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"name": "zkLend Token",
|
|
53
|
-
"symbol": "ZEND",
|
|
54
|
-
"address": "",
|
|
55
|
-
"decimals": 18,
|
|
56
|
-
"pricerKey": "ZEND-USDT"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"name": "Dai Stablecoin",
|
|
60
|
-
"symbol": "DAI",
|
|
61
|
-
"address": "",
|
|
62
|
-
"decimals": 18,
|
|
63
|
-
"pricerKey": "DAI-USDT"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"name": "Ekubo Protocol",
|
|
67
|
-
"symbol": "EKUBO",
|
|
68
|
-
"address": "",
|
|
69
|
-
"decimals": 18,
|
|
70
|
-
"pricerKey": "DAI-USDT"
|
|
71
|
-
}
|
|
72
|
-
]
|