@strkfarm/sdk 1.0.9 → 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 -97
- package/dist/cli.mjs +34 -97
- package/dist/index.browser.global.js +3987 -4034
- package/dist/index.d.ts +29 -27
- package/dist/index.js +119 -165
- package/dist/index.mjs +115 -161
- 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/data/tokens.json +0 -79
package/dist/index.mjs
CHANGED
|
@@ -6,90 +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
|
-
{
|
|
84
|
-
name: "kSTRK token",
|
|
85
|
-
symbol: "kSTRK",
|
|
86
|
-
address: "",
|
|
87
|
-
decimals: 18,
|
|
88
|
-
pricerKey: "DAI-USDT"
|
|
89
|
-
}
|
|
90
|
-
];
|
|
9
|
+
import axios2 from "axios";
|
|
91
10
|
|
|
92
11
|
// src/global.ts
|
|
12
|
+
import axios from "axios";
|
|
93
13
|
var logger = {
|
|
94
14
|
...console,
|
|
95
15
|
verbose(message) {
|
|
@@ -105,6 +25,7 @@ var FatalError = class extends Error {
|
|
|
105
25
|
this.name = "FatalError";
|
|
106
26
|
}
|
|
107
27
|
};
|
|
28
|
+
var tokens = [];
|
|
108
29
|
var Global = class {
|
|
109
30
|
static fatalError(message, err) {
|
|
110
31
|
logger.error(message);
|
|
@@ -118,7 +39,23 @@ var Global = class {
|
|
|
118
39
|
console.error(err);
|
|
119
40
|
}
|
|
120
41
|
static async getTokens() {
|
|
121
|
-
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;
|
|
122
59
|
}
|
|
123
60
|
static assert(condition, message) {
|
|
124
61
|
if (!condition) {
|
|
@@ -127,20 +64,86 @@ var Global = class {
|
|
|
127
64
|
}
|
|
128
65
|
};
|
|
129
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
|
+
|
|
130
131
|
// src/modules/pricer.ts
|
|
131
132
|
var CoinMarketCap = __require("coinmarketcap-api");
|
|
132
133
|
var Pricer = class {
|
|
133
|
-
constructor(config,
|
|
134
|
+
constructor(config, tokens2) {
|
|
134
135
|
this.tokens = [];
|
|
135
136
|
this.prices = {};
|
|
136
137
|
/**
|
|
137
138
|
* TOKENA and TOKENB are the two token names to get price of TokenA in terms of TokenB
|
|
138
139
|
*/
|
|
139
140
|
this.PRICE_API = `https://api.coinbase.com/v2/prices/{{PRICER_KEY}}/buy`;
|
|
140
|
-
|
|
141
|
+
this.EKUBO_API = "https://mainnet-api.ekubo.org/quote/{{AMOUNT}}/{{TOKEN_SYMBOL}}/USDC";
|
|
142
|
+
// e.g. ETH/USDC
|
|
143
|
+
// backup oracle001
|
|
141
144
|
this.client = new CoinMarketCap(process.env.COINMARKETCAP_KEY);
|
|
142
145
|
this.config = config;
|
|
143
|
-
this.tokens =
|
|
146
|
+
this.tokens = tokens2;
|
|
144
147
|
}
|
|
145
148
|
isReady() {
|
|
146
149
|
const allPricesExist = Object.keys(this.prices).length === this.tokens.length;
|
|
@@ -224,7 +227,7 @@ var Pricer = class {
|
|
|
224
227
|
});
|
|
225
228
|
if (this.isReady() && this.config.heartbeatUrl) {
|
|
226
229
|
console.log(`sending beat`);
|
|
227
|
-
|
|
230
|
+
axios2.get(this.config.heartbeatUrl).catch((err) => {
|
|
228
231
|
console.error("Pricer: Heartbeat err", err);
|
|
229
232
|
});
|
|
230
233
|
}
|
|
@@ -238,14 +241,15 @@ var Pricer = class {
|
|
|
238
241
|
return await this._getPriceCoinMarketCap(token);
|
|
239
242
|
} catch (error) {
|
|
240
243
|
}
|
|
244
|
+
try {
|
|
245
|
+
return await this._getPriceEkubo(token);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
}
|
|
241
248
|
throw new FatalError(`Price not found for ${token.name}`);
|
|
242
249
|
}
|
|
243
250
|
async _getPriceCoinbase(token) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
const url = this.PRICE_API.replace("{{PRICER_KEY}}", token.pricerKey);
|
|
248
|
-
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);
|
|
249
253
|
const data = result.data;
|
|
250
254
|
return Number(data.data.amount);
|
|
251
255
|
}
|
|
@@ -253,6 +257,20 @@ var Pricer = class {
|
|
|
253
257
|
const result = await this.client.getQuotes({ symbol: token.symbol });
|
|
254
258
|
return result.data[token.symbol].quote.USD.price;
|
|
255
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
|
+
}
|
|
256
274
|
};
|
|
257
275
|
|
|
258
276
|
// src/modules/pragma.ts
|
|
@@ -374,43 +392,7 @@ var Pragma = class {
|
|
|
374
392
|
};
|
|
375
393
|
|
|
376
394
|
// src/modules/zkLend.ts
|
|
377
|
-
import
|
|
378
|
-
|
|
379
|
-
// src/dataTypes/bignumber.ts
|
|
380
|
-
import BigNumber from "bignumber.js";
|
|
381
|
-
var Web3Number = class _Web3Number extends BigNumber {
|
|
382
|
-
constructor(value, decimals) {
|
|
383
|
-
super(value);
|
|
384
|
-
this.decimals = decimals;
|
|
385
|
-
}
|
|
386
|
-
static fromWei(weiNumber, decimals) {
|
|
387
|
-
const bn = new _Web3Number(weiNumber, decimals).dividedBy(10 ** decimals);
|
|
388
|
-
return new _Web3Number(bn.toString(), decimals);
|
|
389
|
-
}
|
|
390
|
-
toWei() {
|
|
391
|
-
return this.mul(10 ** this.decimals).toFixed(0);
|
|
392
|
-
}
|
|
393
|
-
multipliedBy(value) {
|
|
394
|
-
return new _Web3Number(this.mul(value).toString(), this.decimals);
|
|
395
|
-
}
|
|
396
|
-
dividedBy(value) {
|
|
397
|
-
return new _Web3Number(this.div(value).toString(), this.decimals);
|
|
398
|
-
}
|
|
399
|
-
plus(value) {
|
|
400
|
-
return new _Web3Number(this.add(value).toString(), this.decimals);
|
|
401
|
-
}
|
|
402
|
-
minus(n, base) {
|
|
403
|
-
return new _Web3Number(super.minus(n, base).toString(), this.decimals);
|
|
404
|
-
}
|
|
405
|
-
toString(base) {
|
|
406
|
-
return super.toString(base);
|
|
407
|
-
}
|
|
408
|
-
// [customInspectSymbol](depth: any, inspectOptions: any, inspect: any) {
|
|
409
|
-
// return this.toString();
|
|
410
|
-
// }
|
|
411
|
-
};
|
|
412
|
-
BigNumber.config({ DECIMAL_PLACES: 18 });
|
|
413
|
-
Web3Number.config({ DECIMAL_PLACES: 18 });
|
|
395
|
+
import axios3 from "axios";
|
|
414
396
|
|
|
415
397
|
// src/interfaces/lending.ts
|
|
416
398
|
var MarginType = /* @__PURE__ */ ((MarginType2) => {
|
|
@@ -454,7 +436,7 @@ var _ZkLend = class _ZkLend extends ILending {
|
|
|
454
436
|
async init() {
|
|
455
437
|
try {
|
|
456
438
|
logger.verbose(`Initialising ${this.metadata.name}`);
|
|
457
|
-
const result = await
|
|
439
|
+
const result = await axios3.get(_ZkLend.POOLS_URL);
|
|
458
440
|
const data = result.data;
|
|
459
441
|
const savedTokens = await Global.getTokens();
|
|
460
442
|
data.forEach((pool) => {
|
|
@@ -544,7 +526,7 @@ var _ZkLend = class _ZkLend extends ILending {
|
|
|
544
526
|
*/
|
|
545
527
|
async getPositions(user) {
|
|
546
528
|
const url = this.POSITION_URL.replace("{{USER_ADDR}}", user.address);
|
|
547
|
-
const result = await
|
|
529
|
+
const result = await axios3.get(url);
|
|
548
530
|
const data = result.data;
|
|
549
531
|
const lendingPosition = [];
|
|
550
532
|
logger.verbose(`${this.metadata.name}:: Positions: ${JSON.stringify(data)}`);
|
|
@@ -613,34 +595,6 @@ var Initializable = class {
|
|
|
613
595
|
}
|
|
614
596
|
};
|
|
615
597
|
|
|
616
|
-
// src/dataTypes/address.ts
|
|
617
|
-
import { num } from "starknet";
|
|
618
|
-
var ContractAddr = class _ContractAddr {
|
|
619
|
-
constructor(address) {
|
|
620
|
-
this.address = _ContractAddr.standardise(address);
|
|
621
|
-
}
|
|
622
|
-
static from(address) {
|
|
623
|
-
return new _ContractAddr(address);
|
|
624
|
-
}
|
|
625
|
-
eq(other) {
|
|
626
|
-
return this.address === other.address;
|
|
627
|
-
}
|
|
628
|
-
eqString(other) {
|
|
629
|
-
return this.address === _ContractAddr.standardise(other);
|
|
630
|
-
}
|
|
631
|
-
static standardise(address) {
|
|
632
|
-
let _a = address;
|
|
633
|
-
if (!address) {
|
|
634
|
-
_a = "0";
|
|
635
|
-
}
|
|
636
|
-
const a = num.getHexString(num.getDecimalString(_a.toString()));
|
|
637
|
-
return a;
|
|
638
|
-
}
|
|
639
|
-
static eqString(a, b) {
|
|
640
|
-
return _ContractAddr.standardise(a) === _ContractAddr.standardise(b);
|
|
641
|
-
}
|
|
642
|
-
};
|
|
643
|
-
|
|
644
598
|
// src/strategies/autoCompounderStrk.ts
|
|
645
599
|
import { Contract as Contract2, uint256 } from "starknet";
|
|
646
600
|
var AutoCompounderSTRK = class {
|
|
@@ -908,8 +862,8 @@ var Store = class _Store {
|
|
|
908
862
|
// src/node/pricer-redis.ts
|
|
909
863
|
import { createClient } from "redis";
|
|
910
864
|
var PricerRedis = class extends Pricer {
|
|
911
|
-
constructor(config,
|
|
912
|
-
super(config,
|
|
865
|
+
constructor(config, tokens2) {
|
|
866
|
+
super(config, tokens2);
|
|
913
867
|
this.redisClient = null;
|
|
914
868
|
}
|
|
915
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
|
}
|
package/src/data/tokens.json
DELETED
|
@@ -1,79 +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
|
-
{
|
|
73
|
-
"name": "kSTRK token",
|
|
74
|
-
"symbol": "kSTRK",
|
|
75
|
-
"address": "",
|
|
76
|
-
"decimals": 18,
|
|
77
|
-
"pricerKey": "DAI-USDT"
|
|
78
|
-
}
|
|
79
|
-
]
|