@strkfarm/sdk 2.0.0-staging.7 → 2.0.0-staging.71

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,6 +25,8 @@ export interface RiskFactor {
25
25
  reason?: string; // optional reason for the risk factor
26
26
  }
27
27
 
28
+ export type PriceMethod = 'AvnuApi' | 'Coinbase' | 'Coinmarketcap' | 'Ekubo' | 'Avnu';
29
+
28
30
  export interface TokenInfo {
29
31
  name: string;
30
32
  symbol: string;
@@ -35,6 +37,8 @@ export interface TokenInfo {
35
37
  displayDecimals: number;
36
38
  priceProxySymbol?: string; // for tokens like illiquid tokens, we use a proxy symbol to get the price
37
39
  priceCheckAmount?: number; // for tokens like BTC, doing 1BTC price check may not be ideal, esp on illiquid netwrks like sn
40
+ priceMethod?: PriceMethod; // preferred price source; tried first, then falls back to other methods
41
+ dontPrice?: boolean; // a flag that skips pricer to check these tokens.
38
42
  }
39
43
 
40
44
  export enum Network {
@@ -55,25 +59,24 @@ export interface IProtocol {
55
59
  logo: string;
56
60
  }
57
61
 
58
- // Strategy-level enums
59
- export enum StrategyCategory {
60
- ALL = "all",
61
- BTC = "btc",
62
- META_VAULTS = "meta-vaults",
62
+ export interface ICurator {
63
+ name: string;
64
+ logo: string;
63
65
  }
64
66
 
65
67
  export enum StrategyTag {
66
- EKUBO = "Ekubo",
67
- EVERGREEN = "Evergreen",
68
- HYPER_LST = "Hyper-LST",
69
- VESU = "Vesu",
70
- SENSEI = "Sensei",
71
- ENDUR = "Endur",
72
- BTC = "BTC"
68
+ META_VAULT = "Meta Vaults",
69
+ LEVERED = "Maxx",
70
+ AUTOMATED_LP = "Ekubo",
71
+ BTC = "BTC"
73
72
  }
74
73
 
75
74
  export enum VaultType {
76
- FARMING = "farming"
75
+ LOOPING = "Looping",
76
+ META_VAULT = "Meta Vault",
77
+ DELTA_NEUTRAL = "Delta Neutral",
78
+ AUTOMATED_LP = "Automated LP",
79
+ TVA = "Troves Value Averaging",
77
80
  }
78
81
 
79
82
  // Security metadata enums
@@ -90,6 +93,7 @@ export enum SourceCodeType {
90
93
  export enum AccessControlType {
91
94
  MULTISIG_ACCOUNT = "Multisig Account",
92
95
  STANDARD_ACCOUNT = "Standard Account",
96
+ ROLE_BASED_ACCESS = "Role Based Access",
93
97
  }
94
98
 
95
99
  export enum InstantWithdrawalVault {
@@ -106,7 +110,7 @@ export interface SourceCodeInfo {
106
110
  export interface AccessControlInfo {
107
111
  type: AccessControlType;
108
112
  addresses: ContractAddr[];
109
- timeLock: string;
113
+ timeLock?: string;
110
114
  }
111
115
 
112
116
  export interface SecurityMetadata {
@@ -115,16 +119,13 @@ export interface SecurityMetadata {
115
119
  accessControl: AccessControlInfo;
116
120
  }
117
121
 
118
- // Redemption metadata interfaces
119
- export interface RedemptionExpectedTime {
120
- upto1M: string;
121
- upto10M: string;
122
- above10M: string;
123
- }
124
-
125
122
  export interface RedemptionInfo {
126
123
  instantWithdrawalVault: InstantWithdrawalVault;
127
- expectedRedemptionTime?: RedemptionExpectedTime;
124
+ redemptionsInfo: {
125
+ title: string; // e.g. Upto $1M
126
+ description: string; // e.g. "1-2 hours"
127
+ }[],
128
+ alerts: StrategyAlert[];
128
129
  }
129
130
 
130
131
  export enum FlowChartColors {
@@ -142,7 +143,8 @@ export enum StrategyLiveStatus {
142
143
  ACTIVE = "Active",
143
144
  NEW = "New",
144
145
  COMING_SOON = "Coming Soon",
145
- RETIRED = "Retired",
146
+ DEPRECATED = "Deprecated", // active but not recommended
147
+ RETIRED = "Retired", // not active anymore
146
148
  HOT = "Hot & New 🔥"
147
149
  }
148
150
 
@@ -153,7 +155,6 @@ export interface StrategyAlert {
153
155
  }
154
156
 
155
157
  export interface StrategySettings {
156
- maxTVL?: Web3Number;
157
158
  liveStatus?: StrategyLiveStatus;
158
159
  isPaused?: boolean;
159
160
  isInMaintenance?: boolean;
@@ -169,6 +170,17 @@ export interface StrategySettings {
169
170
  tags?: StrategyTag[];
170
171
  }
171
172
 
173
+ export interface StrategyApyHistoryUIConfig {
174
+ // Defaults to true in UI if omitted.
175
+ showApyHistory?: boolean;
176
+ // Optional message shown when APY history is hidden.
177
+ noApyHistoryMessage?: string;
178
+ }
179
+
180
+ export interface FeeBps {
181
+ performanceFeeBps: number;
182
+ }
183
+
172
184
  /**
173
185
  * @property risk.riskFactor.factor - The risk factors that are considered for the strategy.
174
186
  * @property risk.riskFactor.factor - The value of the risk factor from 0 to 10, 0 being the lowest and 10 being the highest.
@@ -179,6 +191,19 @@ export interface IStrategyMetadata<T> {
179
191
  id: string;
180
192
  name: string;
181
193
  description: string | React.ReactNode;
194
+ /**
195
+ * Optional UI sort priority. Higher shows earlier.
196
+ * Intended for pinning flagship parent vaults (e.g. BTC above STRK).
197
+ */
198
+ priority?: number;
199
+ /**
200
+ * Optional UI config for the variant intro popup (strategy page).
201
+ * Should be identical across strategies that share the same `parentId`.
202
+ */
203
+ variantIntro?: {
204
+ title: string;
205
+ description: string;
206
+ };
182
207
  address: ContractAddr;
183
208
  launchBlock: number;
184
209
  type: "ERC4626" | "ERC721" | "Other";
@@ -195,6 +220,8 @@ export interface IStrategyMetadata<T> {
195
220
  notARisks: RiskType[];
196
221
  };
197
222
  apyMethodology?: string;
223
+ realizedApyMethodology?: string;
224
+ feeBps?: FeeBps;
198
225
  additionalInfo: T;
199
226
  contractDetails: {
200
227
  address: ContractAddr;
@@ -205,13 +232,20 @@ export interface IStrategyMetadata<T> {
205
232
  points?: {multiplier: number, logo: string, toolTip?: string}[];
206
233
  docs?: string;
207
234
  investmentSteps: string[];
208
- curator?: { name: string, logo: string },
235
+ curator?: ICurator,
209
236
  isPreview?: boolean;
210
- category: StrategyCategory;
211
237
  tags?: StrategyTag[];
212
238
  security: SecurityMetadata;
213
239
  redemptionInfo: RedemptionInfo;
240
+ usualTimeToEarnings: null | string; // e.g. "2 weeks" // some strats grow like step functions
241
+ usualTimeToEarningsDescription: null | string; // e.g. "LSTs price on DEX goes up roughly every 2 weeks"
242
+ discontinuationInfo?: {
243
+ date?: Date;
244
+ reason?: React.ReactNode | string;
245
+ info?: React.ReactNode | string;
246
+ };
214
247
  settings?: StrategySettings;
248
+ apyHistoryUIConfig?: StrategyApyHistoryUIConfig;
215
249
  // Legacy field for multi-step strategies (deprecated, use investmentFlows instead)
216
250
  actions?: Array<{
217
251
  name?: string;
@@ -224,6 +258,8 @@ export interface IStrategyMetadata<T> {
224
258
  amount?: string | number;
225
259
  isDeposit?: boolean;
226
260
  }>;
261
+ parentId?: string;
262
+ parentName?: string;
227
263
  }
228
264
 
229
265
  export interface IInvestmentFlow {
@@ -250,6 +286,23 @@ export function getMainnetConfig(
250
286
  };
251
287
  }
252
288
 
289
+ export const getStrategyTagDesciption = (tag: StrategyTag): string => {
290
+ switch (tag) {
291
+ case StrategyTag.META_VAULT:
292
+ return "A meta vault is a vault that auto allocates funds to multiple vaults based on optimal yield opportunities";
293
+ case StrategyTag.LEVERED:
294
+ return "Looping vaults on Endur LSTs with leveraged borrowing of STRK or BTC to increase yield (2-4x higher yield than simply staking)";
295
+ case StrategyTag.AUTOMATED_LP:
296
+ return "Automated LP vaults on Ekubo that rebalance position automatically, ensuring you earn fees efficiently";
297
+ case StrategyTag.BTC:
298
+ return "BTC linked vaults";
299
+ }
300
+ }
301
+
302
+ export const getAllStrategyTags = (): StrategyTag[] => {
303
+ return Object.values(StrategyTag);
304
+ }
305
+
253
306
  export const getRiskExplaination = (riskType: RiskType) => {
254
307
  switch (riskType) {
255
308
  case RiskType.MARKET_RISK:
@@ -322,7 +375,7 @@ export function highlightTextWithLinks(
322
375
  {parts.map((part, i) => {
323
376
  const match = highlights.find(m => m.highlight.toLowerCase() === part.toLowerCase());
324
377
  return match ? (
325
- <a key={i} href={match.link} target="_blank" style={{ color: 'var(--chakra-colors-white)', background: 'var(--chakra-colors-highlight)' }}>
378
+ <a key={i} href={match.link} target="_blank" style={{ color: 'white', background: 'rgba(255, 255, 255, 0.04)' }}>
326
379
  {part}
327
380
  </a>
328
381
  ) : (
@@ -383,4 +436,9 @@ export const Protocols = {
383
436
  VESU: VesuProtocol,
384
437
  ENDUR: EndurProtocol,
385
438
  EXTENDED: ExtendedProtocol
439
+ }
440
+
441
+ export const UnwrapLabsCurator: ICurator = {
442
+ name: "Unwrap Labs",
443
+ logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
386
444
  }
@@ -37,7 +37,7 @@ export class AvnuWrapper {
37
37
  excludeSources = ['Haiko(Solvers)']
38
38
  ): Promise<Quote> {
39
39
  const MAX_RETRY = 5;
40
- // logger.verbose(`${AvnuWrapper.name}: getQuotes => Getting quotes for ${fromToken} -> ${toToken}, amount: ${amountWei}, taker: ${taker}, retry: ${retry}`);
40
+ logger.verbose(`${AvnuWrapper.name}: getQuotes => Getting quotes for ${fromToken} -> ${toToken}, amount: ${amountWei}, taker: ${taker}, retry: ${retry}`);
41
41
  const params: any = {
42
42
  sellTokenAddress: fromToken,
43
43
  buyTokenAddress: toToken,
@@ -2,7 +2,7 @@ import { ContractAddr, Web3Number } from "@/dataTypes";
2
2
  import { IConfig } from "@/interfaces";
3
3
  import { Contract } from "starknet";
4
4
  import ERC20Abi from '@/data/erc20.abi.json';
5
-
5
+ import { uint256 } from "starknet";
6
6
  export class ERC20 {
7
7
  readonly config: IConfig;
8
8
 
@@ -12,7 +12,7 @@ export class ERC20 {
12
12
 
13
13
  contract(addr: string | ContractAddr) {
14
14
  const _addr = typeof addr === 'string' ? addr : addr.address;
15
- return new Contract({abi: ERC20Abi, address: _addr, providerOrAccount: this.config.provider});
15
+ return new Contract({ abi: ERC20Abi, address: _addr, providerOrAccount: this.config.provider });
16
16
  }
17
17
 
18
18
  async balanceOf(token: string | ContractAddr, address: string | ContractAddr, tokenDecimals: number) {
@@ -26,4 +26,20 @@ export class ERC20 {
26
26
  const allowance = await contract.call('allowance', [owner.toString(), spender.toString()]);
27
27
  return Web3Number.fromWei(allowance.toString(), tokenDecimals);
28
28
  }
29
+
30
+ approve(
31
+ token: string | ContractAddr,
32
+ spender: string | ContractAddr,
33
+ amount: Web3Number
34
+ ) {
35
+ const contract = this.contract(token);
36
+ const amountUint256 = uint256.bnToUint256(amount.toWei());
37
+ const approveCall = contract.populate("approve", [
38
+ spender.toString(),
39
+ amountUint256.low.toString(),
40
+ amountUint256.high.toString(),
41
+ ]);
42
+ return approveCall;
43
+ }
44
+
29
45
  }
@@ -1,4 +1,5 @@
1
1
  export * from './pricer';
2
+ export * from './pricer-avnu-api';
2
3
  export * from './pragma';
3
4
  export * from './zkLend';
4
5
  export * from './pricer-from-api';
@@ -6,4 +7,5 @@ export * from './erc20';
6
7
  export * from './avnu';
7
8
  export * from './ekubo-quoter';
8
9
  export * from './pricer-lst';
9
- export * from './lst-apr';
10
+ export * from './lst-apr';
11
+ export * from './ekubo-pricer'
@@ -0,0 +1,114 @@
1
+ import axios from "axios";
2
+ import { TokenInfo } from "@/interfaces/common";
3
+ import { IConfig } from "@/interfaces/common";
4
+ import { PricerBase } from "./pricerBase";
5
+ import { PriceInfo } from "./pricer";
6
+ import { logger } from "@/utils/logger";
7
+ import { ContractAddr } from "@/dataTypes";
8
+
9
+ const AVNU_TOKENS_API = "https://starknet.impulse.avnu.fi/v3/tokens";
10
+
11
+ interface AvnuTokenApiEntry {
12
+ address: string;
13
+ symbol: string;
14
+ starknet?: {
15
+ usd?: number;
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Polls Avnu impulse tokens API and keeps USD prices in memory for configured tokens.
21
+ * Price timestamp is set when each poll request completes.
22
+ */
23
+ export class PricerAvnuApi extends PricerBase {
24
+ protected prices: { [key: string]: PriceInfo } = {};
25
+
26
+ readonly refreshInterval = 15_000;
27
+ readonly staleTime = 5 * 60 * 1000;
28
+
29
+ private pollTimer: ReturnType<typeof setInterval> | null = null;
30
+ private loading = false;
31
+
32
+ constructor(config: IConfig, tokens: TokenInfo[]) {
33
+ super(config, tokens);
34
+ }
35
+
36
+ start() {
37
+ this._loadPrices();
38
+ this.pollTimer = setInterval(() => {
39
+ this._loadPrices();
40
+ }, this.refreshInterval);
41
+ }
42
+
43
+ stop() {
44
+ if (this.pollTimer) {
45
+ clearInterval(this.pollTimer);
46
+ this.pollTimer = null;
47
+ }
48
+ }
49
+
50
+ isStale(timestamp: Date) {
51
+ return Date.now() - timestamp.getTime() > this.staleTime;
52
+ }
53
+
54
+ hasPrice(tokenSymbol: string) {
55
+ const info = this.prices[tokenSymbol];
56
+ return !!info && !this.isStale(info.timestamp);
57
+ }
58
+
59
+ async getPrice(tokenSymbol: string): Promise<PriceInfo> {
60
+ const info = this.prices[tokenSymbol];
61
+ if (!info) {
62
+ throw new Error(`AvnuApi: price of ${tokenSymbol} not found`);
63
+ }
64
+ if (this.isStale(info.timestamp)) {
65
+ throw new Error(`AvnuApi: price of ${tokenSymbol} is stale`);
66
+ }
67
+ return info;
68
+ }
69
+
70
+ protected async _loadPrices() {
71
+ if (this.loading) {
72
+ return;
73
+ }
74
+ this.loading = true;
75
+ const timestamp = new Date();
76
+ try {
77
+ const result = await axios.get<AvnuTokenApiEntry[]>(AVNU_TOKENS_API);
78
+ const priceByAddress = new Map<string, number>();
79
+ for (const entry of result.data) {
80
+ const usd = entry.starknet?.usd;
81
+ if (usd != null && usd > 0) {
82
+ priceByAddress.set(ContractAddr.standardise(entry.address), usd);
83
+ }
84
+ }
85
+
86
+ for (const token of this.tokens) {
87
+ if (token.symbol === "USDT" || token.symbol === "USDC") {
88
+ this.prices[token.symbol] = { price: 1, timestamp };
89
+ continue;
90
+ }
91
+
92
+ const targetToken = token.priceProxySymbol
93
+ ? this.tokens.find((t) => t.symbol === token.priceProxySymbol)
94
+ : token;
95
+ if (!targetToken) {
96
+ continue;
97
+ }
98
+
99
+ const addr = targetToken.address.address;
100
+ const price = priceByAddress.get(addr);
101
+ if (price != null) {
102
+ this.prices[token.symbol] = { price, timestamp };
103
+ logger.verbose(
104
+ `AvnuApi: ${token.symbol} -> $${price}`,
105
+ );
106
+ }
107
+ }
108
+ } catch (error: any) {
109
+ logger.warn(`AvnuApi: failed to fetch tokens: ${error?.message ?? error}`);
110
+ } finally {
111
+ this.loading = false;
112
+ }
113
+ }
114
+ }
@@ -1,18 +1,27 @@
1
1
  import axios from "axios";
2
2
  import { FatalError, Global } from "@/global";
3
- import { TokenInfo } from "@/interfaces/common";
3
+ import { PriceMethod, 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
  import { logger } from "@/utils/logger";
8
8
  import { AvnuWrapper } from "./avnu";
9
9
  import { BlockIdentifier } from "starknet";
10
+ import { PricerAvnuApi } from "./pricer-avnu-api";
10
11
 
11
12
  export interface PriceInfo {
12
13
  price: number,
13
14
  timestamp: Date
14
15
  }
15
16
 
17
+ const PRICE_METHOD_PRIORITY: PriceMethod[] = [
18
+ 'AvnuApi',
19
+ 'Coinbase',
20
+ 'Coinmarketcap',
21
+ 'Ekubo',
22
+ 'Avnu',
23
+ ];
24
+
16
25
  export class Pricer extends PricerBase {
17
26
  protected prices: {
18
27
  [key: string]: PriceInfo
@@ -21,9 +30,11 @@ export class Pricer extends PricerBase {
21
30
  refreshInterval = 30000;
22
31
  staleTime = 60000;
23
32
 
33
+ protected readonly avnuApiPricer: PricerAvnuApi;
34
+
24
35
  // code populates this map during runtime to determine which method to use for a given token
25
36
  // The method set will be the first one to try after first attempt
26
- protected methodToUse: {[tokenSymbol: string]: 'Ekubo' | 'Coinbase' | 'Coinmarketcap' | 'Avnu'} = {};
37
+ protected methodToUse: {[tokenSymbol: string]: PriceMethod} = {};
27
38
 
28
39
  /**
29
40
  * TOKENA and TOKENB are the two token names to get price of TokenA in terms of TokenB
@@ -36,6 +47,7 @@ export class Pricer extends PricerBase {
36
47
  super(config, tokens);
37
48
  this.refreshInterval = refreshInterval;
38
49
  this.staleTime = staleTime;
50
+ this.avnuApiPricer = new PricerAvnuApi(config, tokens);
39
51
  }
40
52
 
41
53
  isReady() {
@@ -69,6 +81,7 @@ export class Pricer extends PricerBase {
69
81
  }
70
82
 
71
83
  start() {
84
+ this.avnuApiPricer.start();
72
85
  this._loadPrices();
73
86
  setInterval(() => {
74
87
  this._loadPrices();
@@ -96,6 +109,9 @@ export class Pricer extends PricerBase {
96
109
  let retry = 0;
97
110
  while (retry < MAX_RETRIES) {
98
111
  try {
112
+ if (token.dontPrice) {
113
+ return;
114
+ }
99
115
  if (token.symbol === 'USDT' || token.symbol === 'USDC') {
100
116
  this.prices[token.symbol] = {
101
117
  price: 1,
@@ -145,56 +161,70 @@ export class Pricer extends PricerBase {
145
161
  }
146
162
  }
147
163
 
148
- async _getPrice(token: TokenInfo, defaultMethod = 'all'): Promise<number> {
149
- const methodToUse: string = this.methodToUse[token.symbol] || defaultMethod; // default start with coinbase
150
- logger.verbose(`Fetching price of ${token.symbol} using ${methodToUse}`);
151
- switch (methodToUse) {
164
+ async _getPrice(token: TokenInfo): Promise<number> {
165
+ const methodsToTry = this._getMethodsToTry(token);
166
+
167
+ for (const method of methodsToTry) {
168
+ logger.verbose(`Fetching price of ${token.symbol} using ${method}`);
169
+ try {
170
+ const result = await this._tryPriceMethod(token, method);
171
+ if (!token.priceMethod) {
172
+ this.methodToUse[token.symbol] = method;
173
+ }
174
+ return result;
175
+ } catch (error: any) {
176
+ console.warn(`${method}: price err [${token.symbol}]: `, error.message);
177
+ }
178
+ }
179
+
180
+ throw new FatalError(`Price not found for ${token.symbol}`);
181
+ }
182
+
183
+ protected _getMethodsToTry(token: TokenInfo): PriceMethod[] {
184
+ const methods: PriceMethod[] = [];
185
+
186
+ if (token.priceMethod) {
187
+ methods.push(token.priceMethod);
188
+ }
189
+
190
+ const pinned = this.methodToUse[token.symbol];
191
+ if (pinned && pinned !== token.priceMethod) {
192
+ methods.push(pinned);
193
+ }
194
+
195
+ for (const method of PRICE_METHOD_PRIORITY) {
196
+ if (!methods.includes(method)) {
197
+ methods.push(method);
198
+ }
199
+ }
200
+
201
+ return methods;
202
+ }
203
+
204
+ protected async _tryPriceMethod(token: TokenInfo, method: PriceMethod): Promise<number> {
205
+ switch (method) {
206
+ case 'AvnuApi':
207
+ return await this._getPriceAvnuApi(token);
152
208
  case 'Coinbase':
153
- // try {
154
- // const result = await this._getPriceCoinbase(token);
155
- // this.methodToUse[token.symbol] = 'Coinbase';
156
- // return result;
157
- // } catch (error: any) {
158
- // console.warn(`Coinbase: price err: message [${token.symbol}]: `, error.message);
159
- // // do nothing, try next
160
- // }
209
+ return await this._getPriceCoinbase(token);
161
210
  case 'Coinmarketcap':
162
- try {
163
- const result = await this._getPriceCoinMarketCap(token);
164
- this.methodToUse[token.symbol] = 'Coinmarketcap';
165
- return result;
166
- } catch (error: any) {
167
- console.warn(`CoinMarketCap: price err [${token.symbol}]: `, Object.keys(error));
168
- console.warn(`CoinMarketCap: price err [${token.symbol}]: `, error.message);
169
- }
211
+ return await this._getPriceCoinMarketCap(token);
170
212
  case 'Ekubo':
171
- try {
172
- const result = await this._getPriceEkubo(token, new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals));
173
- this.methodToUse[token.symbol] = 'Ekubo';
174
- return result;
175
- } catch (error: any) {
176
- console.warn(`Ekubo: price err [${token.symbol}]: `, error.message);
177
- console.warn(`Ekubo: price err [${token.symbol}]: `, Object.keys(error));
178
- // do nothing, try next
179
- }
213
+ return await this._getPriceEkubo(
214
+ token,
215
+ new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals),
216
+ );
180
217
  case 'Avnu':
181
- try {
182
- const result = await this._getAvnuPrice(token, new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals));
183
- this.methodToUse[token.symbol] = 'Avnu';
184
- return result;
185
- } catch (error: any) {
186
- console.warn(`Avnu: price err [${token.symbol}]: `, error.message);
187
- console.warn(`Avnu: price err [${token.symbol}]: `, Object.keys(error));
188
- }
189
- }
190
-
191
- // if methodToUse is the default one, pass Coinbase to try all from start
192
- if (defaultMethod == 'all') {
193
- // try again with coinbase
194
- return await this._getPrice(token, 'Coinbase');
218
+ return await this._getAvnuPrice(
219
+ token,
220
+ new Web3Number(token.priceCheckAmount ? token.priceCheckAmount : 1, token.decimals),
221
+ );
195
222
  }
223
+ }
196
224
 
197
- throw new FatalError(`Price not found for ${token.symbol}`);
225
+ async _getPriceAvnuApi(token: TokenInfo): Promise<number> {
226
+ const priceInfo = await this.avnuApiPricer.getPrice(token.symbol);
227
+ return priceInfo.price;
198
228
  }
199
229
 
200
230
  async _getPriceCoinbase(token: TokenInfo) {
@@ -18,6 +18,7 @@ export class PricerRedis extends Pricer {
18
18
  await this.initRedis(redisUrl);
19
19
 
20
20
  logger.info(`Starting Pricer with Redis`);
21
+ this.avnuApiPricer.start();
21
22
  this._loadPrices(this._setRedisPrices.bind(this));
22
23
  setInterval(() => {
23
24
  this._loadPrices(this._setRedisPrices.bind(this));