Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,8 @@ Swagger documentation available at: `http://localhost:3001/swagger`
## CoinGecko

The monitoring service needs a CoinGecko-compatible endpoint for USD/EUR
and USD/CHF FX rates (drives EUR-denominated price conversions and the
staleness watchdog) and the daily Pro quota probe. Configuration is two
env vars:
and USD/CHF FX rates — they drive EUR-denominated price conversions and
the staleness watchdog. Configuration is two env vars:

| Var | Required | Purpose |
|---|---|---|
Expand Down
45 changes: 0 additions & 45 deletions src/monitoringV2/price.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,8 @@ interface CoingeckoEndpoint {
headers: Record<string, string>;
}

interface CoingeckoKeyInfo {
plan?: string;
monthly_call_credit?: number;
current_total_monthly_calls?: number;
current_remaining_monthly_calls?: number;
}

const STALENESS_ALERT_THRESHOLD_MS = 60 * 60 * 1000;
const STALENESS_ALERT_REPEAT_MS = 6 * 60 * 60 * 1000;
const QUOTA_REMAINING_ALERT_THRESHOLD = 25_000;
const QUOTA_ALERT_REPEAT_MS = 24 * 60 * 60 * 1000;

@Injectable()
export class PriceService {
Expand All @@ -63,7 +54,6 @@ export class PriceService {
// suppress the alert indefinitely.
private fxLastSuccessMs: number = Date.now();
private fxStalenessAlertedAt: number | null = null;
private quotaAlertedAt: number | null = null;

constructor(
private readonly providerService: ProviderService,
Expand Down Expand Up @@ -307,41 +297,6 @@ export class PriceService {
);
}

/**
* Daily probe of /api/v3/key through the pricing proxy. Emits a critical
* alert when the monthly remaining call credit drops below
* QUOTA_REMAINING_ALERT_THRESHOLD.
*/
@Cron(CronExpression.EVERY_DAY_AT_NOON)
async checkCoingeckoQuota(): Promise<void> {
try {
const { baseUrl, headers } = this.resolveCoingeckoEndpoint();
const response = await axios.get<CoingeckoKeyInfo>(`${baseUrl}/api/v3/key`, {
headers,
timeout: 10000,
});
const { current_remaining_monthly_calls: remaining, monthly_call_credit: credit } = response.data;
if (typeof remaining !== 'number' || typeof credit !== 'number' || credit <= 0) return;

const pct = Math.round((remaining / credit) * 100);
this.logger.log(`CoinGecko quota: ${remaining} of ${credit} calls remaining (${pct}%)`);

if (remaining >= QUOTA_REMAINING_ALERT_THRESHOLD) {
this.quotaAlertedAt = null;
return;
}
if (this.quotaAlertedAt && Date.now() - this.quotaAlertedAt < QUOTA_ALERT_REPEAT_MS) return;

this.quotaAlertedAt = Date.now();
await this.telegramService.sendCriticalAlert(
`CoinGecko monthly quota almost exhausted: ${remaining.toLocaleString()} of ` +
`${credit.toLocaleString()} calls remaining (${pct}%).`
);
} catch (error) {
this.logger.warn(`CoinGecko quota probe failed: ${error.message ?? error}`);
}
}

// Cache management methods

private getFromCache(addresses: string[]): { [key: string]: string } {
Expand Down
Loading