@exagent/agent 0.1.11 → 0.1.13
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/chunk-5NE2K3WU.mjs +2852 -0
- package/dist/chunk-BSNYL2DK.mjs +3005 -0
- package/dist/chunk-BZLZQCKQ.mjs +2853 -0
- package/dist/chunk-DZMU25QF.mjs +3021 -0
- package/dist/chunk-TBITVAFT.mjs +2780 -0
- package/dist/chunk-ZY3ZSYNN.mjs +3023 -0
- package/dist/cli.js +545 -267
- package/dist/cli.mjs +3 -3
- package/dist/index.d.mts +99 -47
- package/dist/index.d.ts +99 -47
- package/dist/index.js +547 -267
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/templates/.env.template +3 -4
- package/templates/docker-compose.yml +1 -1
- package/templates/strategy.template.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -35,36 +35,42 @@ declare const TradingConfigSchema: z.ZodObject<{
|
|
|
35
35
|
maxDailyLossBps: z.ZodDefault<z.ZodNumber>;
|
|
36
36
|
maxConcurrentPositions: z.ZodDefault<z.ZodNumber>;
|
|
37
37
|
tradingIntervalMs: z.ZodDefault<z.ZodNumber>;
|
|
38
|
+
maxSlippageBps: z.ZodDefault<z.ZodNumber>;
|
|
39
|
+
minTradeValueUSD: z.ZodDefault<z.ZodNumber>;
|
|
38
40
|
}, "strip", z.ZodTypeAny, {
|
|
39
41
|
timeHorizon: "intraday" | "swing" | "position";
|
|
40
42
|
maxPositionSizeBps: number;
|
|
41
43
|
maxDailyLossBps: number;
|
|
42
44
|
maxConcurrentPositions: number;
|
|
43
45
|
tradingIntervalMs: number;
|
|
46
|
+
maxSlippageBps: number;
|
|
47
|
+
minTradeValueUSD: number;
|
|
44
48
|
}, {
|
|
45
49
|
timeHorizon?: "intraday" | "swing" | "position" | undefined;
|
|
46
50
|
maxPositionSizeBps?: number | undefined;
|
|
47
51
|
maxDailyLossBps?: number | undefined;
|
|
48
52
|
maxConcurrentPositions?: number | undefined;
|
|
49
53
|
tradingIntervalMs?: number | undefined;
|
|
54
|
+
maxSlippageBps?: number | undefined;
|
|
55
|
+
minTradeValueUSD?: number | undefined;
|
|
50
56
|
}>;
|
|
51
57
|
type TradingConfig = z.infer<typeof TradingConfigSchema>;
|
|
52
|
-
declare const VaultPolicySchema: z.ZodEnum<["disabled", "manual"
|
|
58
|
+
declare const VaultPolicySchema: z.ZodEnum<["disabled", "manual"]>;
|
|
53
59
|
type VaultPolicy = z.infer<typeof VaultPolicySchema>;
|
|
54
60
|
declare const VaultConfigSchema: z.ZodObject<{
|
|
55
|
-
policy: z.ZodDefault<z.ZodEnum<["disabled", "manual"
|
|
61
|
+
policy: z.ZodDefault<z.ZodEnum<["disabled", "manual"]>>;
|
|
56
62
|
defaultName: z.ZodOptional<z.ZodString>;
|
|
57
63
|
defaultSymbol: z.ZodOptional<z.ZodString>;
|
|
58
64
|
feeRecipient: z.ZodOptional<z.ZodString>;
|
|
59
65
|
preferVaultTrading: z.ZodDefault<z.ZodBoolean>;
|
|
60
66
|
}, "strip", z.ZodTypeAny, {
|
|
61
|
-
policy: "disabled" | "manual"
|
|
67
|
+
policy: "disabled" | "manual";
|
|
62
68
|
preferVaultTrading: boolean;
|
|
63
69
|
defaultName?: string | undefined;
|
|
64
70
|
defaultSymbol?: string | undefined;
|
|
65
71
|
feeRecipient?: string | undefined;
|
|
66
72
|
}, {
|
|
67
|
-
policy?: "disabled" | "manual" |
|
|
73
|
+
policy?: "disabled" | "manual" | undefined;
|
|
68
74
|
defaultName?: string | undefined;
|
|
69
75
|
defaultSymbol?: string | undefined;
|
|
70
76
|
feeRecipient?: string | undefined;
|
|
@@ -88,7 +94,7 @@ type RelayConfig$1 = z.infer<typeof RelayConfigSchema>;
|
|
|
88
94
|
declare const AgentConfigSchema: z.ZodObject<{
|
|
89
95
|
agentId: z.ZodUnion<[z.ZodNumber, z.ZodString]>;
|
|
90
96
|
name: z.ZodString;
|
|
91
|
-
network: z.ZodDefault<z.
|
|
97
|
+
network: z.ZodDefault<z.ZodLiteral<"mainnet">>;
|
|
92
98
|
wallet: z.ZodOptional<z.ZodObject<{
|
|
93
99
|
setup: z.ZodDefault<z.ZodEnum<["generate", "provide"]>>;
|
|
94
100
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -125,33 +131,39 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
125
131
|
maxDailyLossBps: z.ZodDefault<z.ZodNumber>;
|
|
126
132
|
maxConcurrentPositions: z.ZodDefault<z.ZodNumber>;
|
|
127
133
|
tradingIntervalMs: z.ZodDefault<z.ZodNumber>;
|
|
134
|
+
maxSlippageBps: z.ZodDefault<z.ZodNumber>;
|
|
135
|
+
minTradeValueUSD: z.ZodDefault<z.ZodNumber>;
|
|
128
136
|
}, "strip", z.ZodTypeAny, {
|
|
129
137
|
timeHorizon: "intraday" | "swing" | "position";
|
|
130
138
|
maxPositionSizeBps: number;
|
|
131
139
|
maxDailyLossBps: number;
|
|
132
140
|
maxConcurrentPositions: number;
|
|
133
141
|
tradingIntervalMs: number;
|
|
142
|
+
maxSlippageBps: number;
|
|
143
|
+
minTradeValueUSD: number;
|
|
134
144
|
}, {
|
|
135
145
|
timeHorizon?: "intraday" | "swing" | "position" | undefined;
|
|
136
146
|
maxPositionSizeBps?: number | undefined;
|
|
137
147
|
maxDailyLossBps?: number | undefined;
|
|
138
148
|
maxConcurrentPositions?: number | undefined;
|
|
139
149
|
tradingIntervalMs?: number | undefined;
|
|
150
|
+
maxSlippageBps?: number | undefined;
|
|
151
|
+
minTradeValueUSD?: number | undefined;
|
|
140
152
|
}>>;
|
|
141
153
|
vault: z.ZodDefault<z.ZodObject<{
|
|
142
|
-
policy: z.ZodDefault<z.ZodEnum<["disabled", "manual"
|
|
154
|
+
policy: z.ZodDefault<z.ZodEnum<["disabled", "manual"]>>;
|
|
143
155
|
defaultName: z.ZodOptional<z.ZodString>;
|
|
144
156
|
defaultSymbol: z.ZodOptional<z.ZodString>;
|
|
145
157
|
feeRecipient: z.ZodOptional<z.ZodString>;
|
|
146
158
|
preferVaultTrading: z.ZodDefault<z.ZodBoolean>;
|
|
147
159
|
}, "strip", z.ZodTypeAny, {
|
|
148
|
-
policy: "disabled" | "manual"
|
|
160
|
+
policy: "disabled" | "manual";
|
|
149
161
|
preferVaultTrading: boolean;
|
|
150
162
|
defaultName?: string | undefined;
|
|
151
163
|
defaultSymbol?: string | undefined;
|
|
152
164
|
feeRecipient?: string | undefined;
|
|
153
165
|
}, {
|
|
154
|
-
policy?: "disabled" | "manual" |
|
|
166
|
+
policy?: "disabled" | "manual" | undefined;
|
|
155
167
|
defaultName?: string | undefined;
|
|
156
168
|
defaultSymbol?: string | undefined;
|
|
157
169
|
feeRecipient?: string | undefined;
|
|
@@ -174,7 +186,7 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
174
186
|
}, "strip", z.ZodTypeAny, {
|
|
175
187
|
agentId: string | number;
|
|
176
188
|
name: string;
|
|
177
|
-
network: "mainnet"
|
|
189
|
+
network: "mainnet";
|
|
178
190
|
llm: {
|
|
179
191
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
180
192
|
temperature: number;
|
|
@@ -190,9 +202,11 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
190
202
|
maxDailyLossBps: number;
|
|
191
203
|
maxConcurrentPositions: number;
|
|
192
204
|
tradingIntervalMs: number;
|
|
205
|
+
maxSlippageBps: number;
|
|
206
|
+
minTradeValueUSD: number;
|
|
193
207
|
};
|
|
194
208
|
vault: {
|
|
195
|
-
policy: "disabled" | "manual"
|
|
209
|
+
policy: "disabled" | "manual";
|
|
196
210
|
preferVaultTrading: boolean;
|
|
197
211
|
defaultName?: string | undefined;
|
|
198
212
|
defaultSymbol?: string | undefined;
|
|
@@ -218,7 +232,7 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
218
232
|
temperature?: number | undefined;
|
|
219
233
|
maxTokens?: number | undefined;
|
|
220
234
|
};
|
|
221
|
-
network?: "mainnet" |
|
|
235
|
+
network?: "mainnet" | undefined;
|
|
222
236
|
wallet?: {
|
|
223
237
|
setup?: "generate" | "provide" | undefined;
|
|
224
238
|
} | undefined;
|
|
@@ -229,9 +243,11 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
229
243
|
maxDailyLossBps?: number | undefined;
|
|
230
244
|
maxConcurrentPositions?: number | undefined;
|
|
231
245
|
tradingIntervalMs?: number | undefined;
|
|
246
|
+
maxSlippageBps?: number | undefined;
|
|
247
|
+
minTradeValueUSD?: number | undefined;
|
|
232
248
|
} | undefined;
|
|
233
249
|
vault?: {
|
|
234
|
-
policy?: "disabled" | "manual" |
|
|
250
|
+
policy?: "disabled" | "manual" | undefined;
|
|
235
251
|
defaultName?: string | undefined;
|
|
236
252
|
defaultSymbol?: string | undefined;
|
|
237
253
|
feeRecipient?: string | undefined;
|
|
@@ -253,6 +269,17 @@ interface MarketData {
|
|
|
253
269
|
prices: Record<string, number>;
|
|
254
270
|
balances: Record<string, bigint>;
|
|
255
271
|
portfolioValue: number;
|
|
272
|
+
/** 24h trading volume in USD per token */
|
|
273
|
+
volume24h?: Record<string, number>;
|
|
274
|
+
/** 24h price change percentage per token */
|
|
275
|
+
priceChange24h?: Record<string, number>;
|
|
276
|
+
/** Current Base gas price in wei */
|
|
277
|
+
gasPrice?: bigint;
|
|
278
|
+
/** Network context */
|
|
279
|
+
network?: {
|
|
280
|
+
chainId: number;
|
|
281
|
+
blockNumber?: number;
|
|
282
|
+
};
|
|
256
283
|
}
|
|
257
284
|
interface TradeSignal {
|
|
258
285
|
action: 'buy' | 'sell' | 'hold';
|
|
@@ -289,7 +316,7 @@ interface LLMMetadata {
|
|
|
289
316
|
* Vault Manager for Trading Agents
|
|
290
317
|
*
|
|
291
318
|
* Handles vault creation, qualification checking, and vault-aware trading.
|
|
292
|
-
* Respects the agent's vault policy (disabled, manual
|
|
319
|
+
* Respects the agent's vault policy (disabled, manual).
|
|
293
320
|
*/
|
|
294
321
|
|
|
295
322
|
interface VaultStatus {
|
|
@@ -301,14 +328,13 @@ interface VaultStatus {
|
|
|
301
328
|
requirementsMet: boolean;
|
|
302
329
|
requirements: {
|
|
303
330
|
veXARequired: bigint;
|
|
304
|
-
burnFee: bigint;
|
|
305
331
|
isBypassed: boolean;
|
|
306
332
|
};
|
|
307
333
|
}
|
|
308
334
|
interface VaultManagerConfig {
|
|
309
335
|
agentId: bigint;
|
|
310
336
|
agentName: string;
|
|
311
|
-
network: 'mainnet'
|
|
337
|
+
network: 'mainnet';
|
|
312
338
|
walletKey: `0x${string}`;
|
|
313
339
|
vaultConfig: VaultConfig;
|
|
314
340
|
}
|
|
@@ -325,6 +351,7 @@ declare class VaultManager {
|
|
|
325
351
|
private cachedVaultAddress;
|
|
326
352
|
private lastVaultCheck;
|
|
327
353
|
private readonly VAULT_CACHE_TTL;
|
|
354
|
+
private enabled;
|
|
328
355
|
constructor(config: VaultManagerConfig);
|
|
329
356
|
/**
|
|
330
357
|
* Get the agent's vault policy
|
|
@@ -340,28 +367,22 @@ declare class VaultManager {
|
|
|
340
367
|
getVaultStatus(): Promise<VaultStatus>;
|
|
341
368
|
/**
|
|
342
369
|
* Get vault creation requirements
|
|
370
|
+
* Note: No burnFee on mainnet — vault creation requires USDC seed instead
|
|
343
371
|
*/
|
|
344
372
|
getRequirements(): Promise<{
|
|
345
373
|
veXARequired: bigint;
|
|
346
|
-
burnFee: bigint;
|
|
347
374
|
isBypassed: boolean;
|
|
348
375
|
}>;
|
|
349
376
|
/**
|
|
350
377
|
* Get the agent's vault address (cached)
|
|
351
378
|
*/
|
|
352
379
|
getVaultAddress(): Promise<Address | null>;
|
|
353
|
-
/**
|
|
354
|
-
* Check if the agent should create a vault based on policy and qualification
|
|
355
|
-
*/
|
|
356
|
-
shouldCreateVault(): Promise<{
|
|
357
|
-
should: boolean;
|
|
358
|
-
reason: string;
|
|
359
|
-
}>;
|
|
360
380
|
/**
|
|
361
381
|
* Create a vault for the agent
|
|
382
|
+
* @param seedAmount - USDC seed amount in raw units (default: 100e6 = 100 USDC)
|
|
362
383
|
* @returns Vault address if successful
|
|
363
384
|
*/
|
|
364
|
-
createVault(): Promise<{
|
|
385
|
+
createVault(seedAmount?: bigint): Promise<{
|
|
365
386
|
success: boolean;
|
|
366
387
|
vaultAddress?: Address;
|
|
367
388
|
txHash?: Hash;
|
|
@@ -384,15 +405,6 @@ declare class VaultManager {
|
|
|
384
405
|
txHash?: Hash;
|
|
385
406
|
error?: string;
|
|
386
407
|
} | null>;
|
|
387
|
-
/**
|
|
388
|
-
* Run the auto-creation check (call this periodically in the agent loop)
|
|
389
|
-
* Only creates vault if policy is 'auto_when_qualified'
|
|
390
|
-
*/
|
|
391
|
-
checkAndAutoCreateVault(): Promise<{
|
|
392
|
-
action: 'created' | 'skipped' | 'already_exists' | 'not_qualified';
|
|
393
|
-
vaultAddress?: Address;
|
|
394
|
-
reason: string;
|
|
395
|
-
}>;
|
|
396
408
|
}
|
|
397
409
|
|
|
398
410
|
/**
|
|
@@ -464,13 +476,13 @@ declare class AgentRuntime {
|
|
|
464
476
|
private isRunning;
|
|
465
477
|
private mode;
|
|
466
478
|
private configHash;
|
|
467
|
-
private lastVaultCheck;
|
|
468
479
|
private cycleCount;
|
|
469
480
|
private lastCycleAt;
|
|
470
481
|
private lastPortfolioValue;
|
|
471
482
|
private lastEthBalance;
|
|
472
483
|
private processAlive;
|
|
473
|
-
private
|
|
484
|
+
private riskUniverse;
|
|
485
|
+
private allowedTokens;
|
|
474
486
|
constructor(config: RuntimeConfig);
|
|
475
487
|
/**
|
|
476
488
|
* Initialize the agent runtime
|
|
@@ -490,6 +502,11 @@ declare class AgentRuntime {
|
|
|
490
502
|
* that waits for the owner to link it from the website.
|
|
491
503
|
*/
|
|
492
504
|
private ensureWalletLinked;
|
|
505
|
+
/**
|
|
506
|
+
* Load risk universe and allowed tokens from on-chain registry.
|
|
507
|
+
* This prevents the agent from wasting gas on trades that will revert.
|
|
508
|
+
*/
|
|
509
|
+
private loadTradingRestrictions;
|
|
493
510
|
/**
|
|
494
511
|
* Sync the LLM config hash to chain for epoch tracking.
|
|
495
512
|
* If the wallet has insufficient gas, enters a recovery loop
|
|
@@ -521,13 +538,10 @@ declare class AgentRuntime {
|
|
|
521
538
|
*/
|
|
522
539
|
private runCycle;
|
|
523
540
|
/**
|
|
524
|
-
* Check if ETH balance is below threshold and notify
|
|
541
|
+
* Check if ETH balance is below threshold and notify.
|
|
542
|
+
* Returns true if trading should continue, false if ETH is critically low.
|
|
525
543
|
*/
|
|
526
544
|
private checkFundsLow;
|
|
527
|
-
/**
|
|
528
|
-
* Check for vault auto-creation based on policy
|
|
529
|
-
*/
|
|
530
|
-
private checkVaultAutoCreation;
|
|
531
545
|
/**
|
|
532
546
|
* Stop the agent process completely
|
|
533
547
|
*/
|
|
@@ -537,7 +551,9 @@ declare class AgentRuntime {
|
|
|
537
551
|
*/
|
|
538
552
|
private getRpcUrl;
|
|
539
553
|
/**
|
|
540
|
-
* Default tokens to track
|
|
554
|
+
* Default tokens to track.
|
|
555
|
+
* These are validated against the on-chain registry's isTradeAllowed() during init —
|
|
556
|
+
* agents in restricted risk universes will have ineligible tokens filtered out.
|
|
541
557
|
*/
|
|
542
558
|
private getDefaultTokens;
|
|
543
559
|
private sleep;
|
|
@@ -745,11 +761,14 @@ declare function getAllStrategyTemplates(): StrategyTemplate[];
|
|
|
745
761
|
|
|
746
762
|
/**
|
|
747
763
|
* Trade Executor
|
|
748
|
-
* Handles execution of trade signals through the ExagentRouter
|
|
764
|
+
* Handles execution of trade signals through the ExagentRouter.
|
|
765
|
+
* All trades go through the router — there is no direct DEX bypass.
|
|
766
|
+
* Pre-checks token eligibility to avoid wasting gas on reverts.
|
|
749
767
|
*/
|
|
750
768
|
declare class TradeExecutor {
|
|
751
769
|
private client;
|
|
752
770
|
private config;
|
|
771
|
+
private allowedTokens;
|
|
753
772
|
constructor(client: ExagentClient, config: RuntimeConfig);
|
|
754
773
|
/**
|
|
755
774
|
* Execute a single trade signal
|
|
@@ -770,7 +789,7 @@ declare class TradeExecutor {
|
|
|
770
789
|
error?: string;
|
|
771
790
|
}>>;
|
|
772
791
|
/**
|
|
773
|
-
* Validate a signal against config limits
|
|
792
|
+
* Validate a signal against config limits and token restrictions
|
|
774
793
|
*/
|
|
775
794
|
private validateSignal;
|
|
776
795
|
private delay;
|
|
@@ -783,7 +802,10 @@ declare class TradeExecutor {
|
|
|
783
802
|
declare class RiskManager {
|
|
784
803
|
private config;
|
|
785
804
|
private dailyPnL;
|
|
805
|
+
private dailyFees;
|
|
786
806
|
private lastResetDate;
|
|
807
|
+
/** Minimum trade value in USD — trades below this are rejected as dust */
|
|
808
|
+
private minTradeValueUSD;
|
|
787
809
|
constructor(config: TradingConfig);
|
|
788
810
|
/**
|
|
789
811
|
* Filter signals through risk checks
|
|
@@ -794,6 +816,10 @@ declare class RiskManager {
|
|
|
794
816
|
* Validate individual signal against risk limits
|
|
795
817
|
*/
|
|
796
818
|
private validateSignal;
|
|
819
|
+
/**
|
|
820
|
+
* Count non-zero token positions (excluding native ETH and stablecoins used as base currency)
|
|
821
|
+
*/
|
|
822
|
+
private countActivePositions;
|
|
797
823
|
/**
|
|
798
824
|
* Check if daily loss limit has been hit
|
|
799
825
|
*/
|
|
@@ -803,14 +829,23 @@ declare class RiskManager {
|
|
|
803
829
|
*/
|
|
804
830
|
private estimateSignalValue;
|
|
805
831
|
/**
|
|
806
|
-
* Update daily PnL after a trade
|
|
832
|
+
* Update daily PnL after a trade (market gains/losses only)
|
|
807
833
|
*/
|
|
808
834
|
updatePnL(pnl: number): void;
|
|
835
|
+
/**
|
|
836
|
+
* Update daily fees (trading fees, gas costs, etc.)
|
|
837
|
+
* Fees are tracked separately and do NOT count toward the daily loss limit.
|
|
838
|
+
* This prevents protocol fees from triggering circuit breakers.
|
|
839
|
+
*/
|
|
840
|
+
updateFees(fees: number): void;
|
|
809
841
|
/**
|
|
810
842
|
* Get current risk status
|
|
843
|
+
* @param portfolioValue - Current portfolio value in USD (needed for accurate loss limit)
|
|
811
844
|
*/
|
|
812
|
-
getStatus(): {
|
|
845
|
+
getStatus(portfolioValue?: number): {
|
|
813
846
|
dailyPnL: number;
|
|
847
|
+
dailyFees: number;
|
|
848
|
+
dailyNetPnL: number;
|
|
814
849
|
dailyLossLimit: number;
|
|
815
850
|
isLimitHit: boolean;
|
|
816
851
|
};
|
|
@@ -818,22 +853,39 @@ declare class RiskManager {
|
|
|
818
853
|
|
|
819
854
|
/**
|
|
820
855
|
* Market Data Service
|
|
821
|
-
* Fetches prices and
|
|
856
|
+
* Fetches real prices from CoinGecko and on-chain balances for strategy analysis.
|
|
822
857
|
*
|
|
823
858
|
* Queries real on-chain balances for:
|
|
824
859
|
* - Native ETH (via eth_getBalance)
|
|
825
860
|
* - ERC-20 tokens (via balanceOf)
|
|
861
|
+
*
|
|
862
|
+
* Fetches real prices from CoinGecko free API.
|
|
863
|
+
* Refuses to return data if prices are stale (>60s old) to prevent
|
|
864
|
+
* agents from making decisions with outdated price information.
|
|
826
865
|
*/
|
|
827
866
|
declare class MarketDataService {
|
|
828
867
|
private rpcUrl;
|
|
829
868
|
private client;
|
|
869
|
+
/** Cached prices from last fetch */
|
|
870
|
+
private cachedPrices;
|
|
871
|
+
/** Timestamp of last successful price fetch */
|
|
872
|
+
private lastPriceFetchAt;
|
|
830
873
|
constructor(rpcUrl: string);
|
|
874
|
+
/** Cached volume data */
|
|
875
|
+
private cachedVolume24h;
|
|
876
|
+
/** Cached price change data */
|
|
877
|
+
private cachedPriceChange24h;
|
|
831
878
|
/**
|
|
832
879
|
* Fetch current market data for the agent
|
|
833
880
|
*/
|
|
834
881
|
fetchMarketData(walletAddress: string, tokenAddresses: string[]): Promise<MarketData>;
|
|
835
882
|
/**
|
|
836
|
-
*
|
|
883
|
+
* Check if cached prices are still fresh
|
|
884
|
+
*/
|
|
885
|
+
get pricesAreFresh(): boolean;
|
|
886
|
+
/**
|
|
887
|
+
* Fetch token prices from CoinGecko free API
|
|
888
|
+
* Returns cached prices if still fresh (<60s old)
|
|
837
889
|
*/
|
|
838
890
|
private fetchPrices;
|
|
839
891
|
/**
|