142 lines
5.4 KiB
JavaScript
142 lines
5.4 KiB
JavaScript
// Generated, do not edit. sha256:90b33d041c8c7e24dc16bdda9708154576175dfedc5c9ea7860984b38b588f03
|
|||
|
|
import { listAssets } from '../data/assets.js';
|
||
|
|
import { upsertPriceHistory, getPricePoint, getPriceAt } from '../data/price-history.js';
|
||
|
|
import { onchainAsset } from '../data/tx-links.js';
|
||
|
|
import { liveSpotFor, ensurePriceHistoryFor, hasDailyGridFor, historicalPointForVia, primarySourceKey, lastSpotSource, basePriceOf, rateOn } from '../price/providers.js';
|
||
|
|
import { priceAtMoment } from '../data/market.js';
|
||
|
|
import { baseCurrency } from '../app-settings.js';
|
||
|
|
import { getProvider, listProviders } from '../data/providers.js';
|
||
|
|
import { provenanceOfRow, originFrom, liveOrigin } from '../../shared/price-provenance.js';
|
||
|
|
import { fmtBase, fmtMoney, isBaseAsset, priceFromBase } from './format.js';
|
||
|
|
|
||
|
|
const spot = new Map();
|
||
|
|
const hist = new Map();
|
||
|
|
|
||
|
|
const defaultTarget = async () => onchainAsset();
|
||
|
|
const mainValue = (amountSub, asset) => amountSub / Math.pow(10, asset.decimals ?? 8);
|
||
|
|
const histKey = (assetId, dateKey) => `${assetId}:${dateKey}`;
|
||
|
|
const unixAtMidnight = dateKey => Math.floor(Date.parse(`${dateKey}T00:00:00Z`) / 1000);
|
||
|
|
|
||
|
|
export async function loadFiat(assets = null) {
|
||
|
|
const targets = assets || [await defaultTarget()];
|
||
|
|
for (const asset of targets) {
|
||
|
|
if (!asset) continue;
|
||
|
|
try {
|
||
|
|
const s = await liveSpotFor(asset);
|
||
|
|
spot.set(asset.id, s || { price: null });
|
||
|
|
} catch { }
|
||
|
|
}
|
||
|
|
return spot;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function fiatValue(amountSub, asset) {
|
||
|
|
if (isBaseAsset(asset)) return '';
|
||
|
|
const s = asset && spot.get(asset.id);
|
||
|
|
if (!s) return '';
|
||
|
|
const price = basePriceOf(s);
|
||
|
|
if (price == null) return '';
|
||
|
|
return fmtMoney(mainValue(amountSub, asset) * price, baseCurrency());
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function loadHistorical(items) {
|
||
|
|
if (!namen.size) await laadNamen();
|
||
|
|
const byAsset = new Map();
|
||
|
|
for (const it of items) {
|
||
|
|
if (!it || !it.assetId || !it.dateKey) continue;
|
||
|
|
if (!byAsset.has(it.assetId)) byAsset.set(it.assetId, new Set());
|
||
|
|
byAsset.get(it.assetId).add(it.dateKey);
|
||
|
|
}
|
||
|
|
for (const [assetId, keys] of byAsset) {
|
||
|
|
const asset = (await listAssets()).find(a => a.id === assetId);
|
||
|
|
if (asset) await loadHistoricalForAsset(asset, keys);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadHistoricalForAsset(asset, keys) {
|
||
|
|
const gridSrc = await primarySourceKey(asset, 'daily_history');
|
||
|
|
const pointSrc = await primarySourceKey(asset, 'history_point');
|
||
|
|
const readSrc = gridSrc || pointSrc;
|
||
|
|
const hasGrid = await hasDailyGridFor(asset);
|
||
|
|
const punten = await Promise.all([...keys].map(k => getPricePoint(asset.id, k)));
|
||
|
|
if (hasGrid && punten.some(p => !p)) {
|
||
|
|
try { await ensurePriceHistoryFor(asset); } catch { }
|
||
|
|
}
|
||
|
|
for (const key of keys) {
|
||
|
|
const hk = histKey(asset.id, key);
|
||
|
|
if (hist.has(hk)) continue;
|
||
|
|
const stored = await getPriceAt(asset.id, unixAtMidnight(key), readSrc);
|
||
|
|
if (stored) { hist.set(hk, stored.fiatPrice); histRij.set(hk, stored); continue; }
|
||
|
|
if (!hasGrid) {
|
||
|
|
try {
|
||
|
|
const p = await historicalPointForVia(asset, key);
|
||
|
|
if (p) {
|
||
|
|
await upsertPriceHistory(asset.id, [p], pointSrc, 'day');
|
||
|
|
hist.set(hk, p.price);
|
||
|
|
const bron = await getProvider(pointSrc).catch(() => null);
|
||
|
|
histRij.set(hk, { fiatPrice: p.price, providerId: bron ? bron.id : null, resolution: 'day',
|
||
|
|
observedAt: `${key}T00:00:00Z`, createdAt: new Date().toISOString() });
|
||
|
|
}
|
||
|
|
else hist.set(hk, null);
|
||
|
|
} catch { hist.set(hk, null); }
|
||
|
|
} else {
|
||
|
|
hist.set(hk, null);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function fiatHistorical(amountSub, asset, dateKey) {
|
||
|
|
if (!asset) return '';
|
||
|
|
const price = hist.get(histKey(asset.id, dateKey));
|
||
|
|
if (price == null) return '';
|
||
|
|
return fmtBase(mainValue(amountSub, asset) * price);
|
||
|
|
}
|
||
|
|
|
||
|
|
const histRij = new Map();
|
||
|
|
let namen = new Map();
|
||
|
|
let manualId = null;
|
||
|
|
async function laadNamen() {
|
||
|
|
try {
|
||
|
|
const providers = await listProviders();
|
||
|
|
namen = new Map(providers.map(p => [p.id, p.name]));
|
||
|
|
const m = providers.find(p => p.key === 'manual');
|
||
|
|
manualId = m ? m.id : null;
|
||
|
|
} catch { }
|
||
|
|
}
|
||
|
|
|
||
|
|
export function fiatHistoricalOrigin(asset, dateKey) {
|
||
|
|
if (!asset || isBaseAsset(asset)) return null;
|
||
|
|
const rij = histRij.get(histKey(asset.id, dateKey));
|
||
|
|
return rij ? originFrom(provenanceOfRow(rij, { day: dateKey, manualProviderId: manualId }), namen) : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function fiatValueOrigin(asset) {
|
||
|
|
if (!asset || isBaseAsset(asset)) return null;
|
||
|
|
const s = spot.get(asset.id);
|
||
|
|
const prijs = basePriceOf(s);
|
||
|
|
return prijs != null ? liveOrigin(prijs, lastSpotSource(asset)) : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function spotOnDate(asset, dateKey) {
|
||
|
|
if (!asset || !dateKey) return null;
|
||
|
|
try { await loadHistorical([{ assetId: asset.id, dateKey }]); } catch { }
|
||
|
|
const pt = await getPricePoint(asset.id, dateKey);
|
||
|
|
return pt && pt.fiatPrice != null ? priceFromBase(pt.fiatPrice, asset) : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function spotAtMoment(asset, atIso) {
|
||
|
|
if (!asset || !atIso) return null;
|
||
|
|
try {
|
||
|
|
const r = await priceAtMoment(asset.id, atIso);
|
||
|
|
if (r.status !== 'ok') return null;
|
||
|
|
const rate = await rateOn(r.currency, String(atIso).slice(0, 10));
|
||
|
|
if (rate == null) return null;
|
||
|
|
return { price: priceFromBase(r.price * rate, asset), at: r.at, source: r.source };
|
||
|
|
} catch {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function fiatAtPrice(amountSub, decimals, pricePerUnit) {
|
||
|
|
if (pricePerUnit == null) return '';
|
||
|
|
return fmtBase((amountSub / Math.pow(10, decimals ?? 8)) * pricePerUnit);
|
||
|
|
}
|