Embed cUSDC per-token sample and triple-state in ho-liquidity snapshot.
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m22s
CI/CD Pipeline / Security Scanning (push) Successful in 2m36s
CI/CD Pipeline / Lint and Format (push) Failing after 52s
CI/CD Pipeline / Terraform Validation (push) Failing after 30s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 27s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 31s
Validation / validate-genesis (push) Successful in 35s
Validation / validate-terraform (push) Has been cancelled
Validation / validate-kubernetes (push) Has been cancelled
Validation / validate-smart-contracts (push) Has been cancelled
Validation / validate-documentation (push) Has been cancelled
Validation / validate-security (push) Has been cancelled
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m22s
CI/CD Pipeline / Security Scanning (push) Successful in 2m36s
CI/CD Pipeline / Lint and Format (push) Failing after 52s
CI/CD Pipeline / Terraform Validation (push) Failing after 30s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 27s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 31s
Validation / validate-genesis (push) Successful in 35s
Validation / validate-terraform (push) Has been cancelled
Validation / validate-kubernetes (push) Has been cancelled
Validation / validate-smart-contracts (push) Has been cancelled
Validation / validate-documentation (push) Has been cancelled
Validation / validate-security (push) Has been cancelled
Public ho-liquidity-snapshot now includes perTokenSamples.cUSDC (Blockscout supply vs 1.2× nostro) and tripleState reconcile summary for the explorer dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import { fetchBlockscoutTokenMeta } from './blockscout-token-meta';
|
||||
import { evaluateSupplyNostroMatch, type SupplyNostroMatchInfo } from './omnl-cash-in-bank-audit';
|
||||
import { runTripleStateReconcile, type TripleReconcileReport } from './omnl-triple-reconcile';
|
||||
import { resolveCanonicalPriceUsd } from './canonical-price-oracle';
|
||||
|
||||
const CHAIN_138 = 138;
|
||||
const DEFAULT_CUSDC_ADDRESS = '0xf22258f57794CC8E06237084b353Ab30fFfa640b';
|
||||
|
||||
export interface HoLiquidityTripleStateSummary {
|
||||
aligned?: boolean;
|
||||
breaksCount?: number;
|
||||
generatedAt?: string;
|
||||
}
|
||||
|
||||
export interface HoLiquidityPerTokenSample {
|
||||
address: string;
|
||||
totalSupplyUsd?: number;
|
||||
cashInBankUsd?: number;
|
||||
supplyNostroMatch?: SupplyNostroMatchInfo;
|
||||
}
|
||||
|
||||
function decimalStringToNumber(value?: string, decimals?: number): number | null {
|
||||
if (value == null || value === '') return null;
|
||||
const dec = Number.isInteger(decimals) ? Number(decimals) : 18;
|
||||
try {
|
||||
const raw = BigInt(value);
|
||||
const base = 10n ** BigInt(dec);
|
||||
const whole = raw / base;
|
||||
const frac = raw % base;
|
||||
return Number(whole) + Number(frac) / Number(base);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function readOptionalTripleStateFile(): TripleReconcileReport | null {
|
||||
const candidates = [
|
||||
process.env.OMNL_TRIPLE_RECONCILE_FILE?.trim(),
|
||||
resolve(process.cwd(), 'reports/status/omnl-triple-reconcile-latest.json'),
|
||||
process.env.PROXMOX_ROOT
|
||||
? resolve(process.env.PROXMOX_ROOT, 'reports/status/omnl-triple-reconcile-latest.json')
|
||||
: '',
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
for (const file of candidates) {
|
||||
if (!existsSync(file)) continue;
|
||||
try {
|
||||
return JSON.parse(readFileSync(file, 'utf8')) as TripleReconcileReport;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function loadHoLiquidityTripleStateSummary(): Promise<HoLiquidityTripleStateSummary | undefined> {
|
||||
let triple: TripleReconcileReport | null = null;
|
||||
try {
|
||||
triple = await runTripleStateReconcile(process.env.OMNL_HEALTH_LINE_ID?.trim() || undefined);
|
||||
} catch {
|
||||
triple = null;
|
||||
}
|
||||
|
||||
const fileTriple = readOptionalTripleStateFile();
|
||||
if ((!triple || (triple.breaks?.length ?? 0) > 0) && fileTriple) {
|
||||
triple = fileTriple;
|
||||
} else if (!triple && fileTriple) {
|
||||
triple = fileTriple;
|
||||
}
|
||||
|
||||
if (!triple) return undefined;
|
||||
|
||||
return {
|
||||
aligned: triple.aligned,
|
||||
breaksCount: (triple.breaks || []).length,
|
||||
generatedAt: triple.generatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadCusdcPerTokenSample(input: {
|
||||
cashInBankUsd: number;
|
||||
officeId: number;
|
||||
}): Promise<HoLiquidityPerTokenSample | undefined> {
|
||||
const address = (process.env.CUSDC_ADDRESS_138 || DEFAULT_CUSDC_ADDRESS).toLowerCase();
|
||||
const meta = await fetchBlockscoutTokenMeta(CHAIN_138, address);
|
||||
const decimals = meta?.decimals ?? 6;
|
||||
const supplyUnits = decimalStringToNumber(meta?.totalSupply, decimals);
|
||||
const { priceUsd } = resolveCanonicalPriceUsd(CHAIN_138, address);
|
||||
const pegPriceUsd = priceUsd != null && priceUsd > 0 ? priceUsd : 1;
|
||||
const totalSupplyUsd = supplyUnits != null && supplyUnits > 0 ? supplyUnits * pegPriceUsd : undefined;
|
||||
|
||||
const supplyNostroMatch = evaluateSupplyNostroMatch({
|
||||
totalSupplyUsd,
|
||||
externalNostroCashUsd: input.cashInBankUsd,
|
||||
headOfficeId: input.officeId,
|
||||
});
|
||||
|
||||
return {
|
||||
address,
|
||||
totalSupplyUsd,
|
||||
cashInBankUsd: input.cashInBankUsd > 0 ? input.cashInBankUsd : undefined,
|
||||
supplyNostroMatch,
|
||||
};
|
||||
}
|
||||
@@ -7,6 +7,12 @@ import {
|
||||
type SupplyNostroMatchInfo,
|
||||
} from './omnl-cash-in-bank-audit';
|
||||
import { fineractConfigured } from './omnl-fineract-office-gl';
|
||||
import {
|
||||
loadCusdcPerTokenSample,
|
||||
loadHoLiquidityTripleStateSummary,
|
||||
type HoLiquidityPerTokenSample,
|
||||
type HoLiquidityTripleStateSummary,
|
||||
} from './omnl-ho-liquidity-enrichment';
|
||||
|
||||
export type HoLiquidityAlertSeverity = 'critical' | 'warning' | 'info';
|
||||
|
||||
@@ -25,6 +31,10 @@ export interface HoLiquiditySnapshot {
|
||||
cashInBank: CashInBankAuditSnapshot;
|
||||
reserveCoverage: HoReserveCoverageInfo;
|
||||
aggregateSupplyNostroMatch?: SupplyNostroMatchInfo;
|
||||
perTokenSamples?: {
|
||||
cUSDC?: HoLiquidityPerTokenSample;
|
||||
};
|
||||
tripleState?: HoLiquidityTripleStateSummary;
|
||||
alerts: HoLiquidityAlert[];
|
||||
auditMaxAgeMinutes: number;
|
||||
}
|
||||
@@ -149,6 +159,14 @@ export async function buildHoLiquiditySnapshot(options?: {
|
||||
),
|
||||
).toISOString();
|
||||
|
||||
const [tripleState, cusdcSample] = await Promise.all([
|
||||
loadHoLiquidityTripleStateSummary().catch(() => undefined),
|
||||
loadCusdcPerTokenSample({
|
||||
cashInBankUsd: cashInBankEnriched.cashInBankUsd,
|
||||
officeId,
|
||||
}).catch(() => undefined),
|
||||
]);
|
||||
|
||||
return {
|
||||
generatedAt,
|
||||
officeId,
|
||||
@@ -158,6 +176,8 @@ export async function buildHoLiquiditySnapshot(options?: {
|
||||
cashInBank: cashInBankEnriched,
|
||||
reserveCoverage,
|
||||
aggregateSupplyNostroMatch,
|
||||
perTokenSamples: cusdcSample ? { cUSDC: cusdcSample } : undefined,
|
||||
tripleState,
|
||||
alerts: evaluateHoLiquidityAlerts({ cashInBank: cashInBankEnriched, reserveCoverage, generatedAt }),
|
||||
auditMaxAgeMinutes: auditMaxAgeMinutes(),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user