diff --git a/frontend-dapp/src/features/central-bank/useCentralBank.ts b/frontend-dapp/src/features/central-bank/useCentralBank.ts index 4758339..ec338e6 100644 --- a/frontend-dapp/src/features/central-bank/useCentralBank.ts +++ b/frontend-dapp/src/features/central-bank/useCentralBank.ts @@ -13,11 +13,16 @@ export type MoneySupply = { }; async function loadMoneySupply(): Promise { - const publicRes = await fetch(settlementApi('/public/money-supply')); - if (publicRes.ok) return publicRes.json(); + for (const path of ['/public/money-supply', '/money-supply/public']) { + const res = await fetch(settlementApi(path)); + if (res.ok) return res.json(); + } - const legacyRes = await fetch(settlementApi('/money-supply/public')); - if (legacyRes.ok) return legacyRes.json(); + const healthRes = await fetch(`${settlementApi('/health')}?ledger=1`); + if (healthRes.ok) { + const data = (await healthRes.json()) as { moneySupply?: MoneySupply }; + if (data.moneySupply) return data.moneySupply; + } const apiKey = import.meta.env.VITE_OMNL_API_KEY; if (!apiKey) return null; diff --git a/frontend-dapp/src/features/office24/useOffice24.ts b/frontend-dapp/src/features/office24/useOffice24.ts index 857efea..1b84376 100644 --- a/frontend-dapp/src/features/office24/useOffice24.ts +++ b/frontend-dapp/src/features/office24/useOffice24.ts @@ -10,6 +10,19 @@ export type M2Token = DexToken & { transferableExternal?: boolean; }; +async function loadOfficeMoneySupply(): Promise { + for (const path of ['/public/money-supply', '/money-supply/public']) { + const res = await fetch(settlementApi(path)); + if (res.ok) return res.json(); + } + const healthRes = await fetch(`${settlementApi('/health')}?ledger=1`); + if (healthRes.ok) { + const data = (await healthRes.json()) as { moneySupply?: MoneySupply }; + if (data.moneySupply) return data.moneySupply; + } + return null; +} + export function useOffice24() { const [office, setOffice] = useState | null>(null); const [tokens, setTokens] = useState([]); @@ -24,7 +37,7 @@ export function useOffice24() { fetch(settlementApi('/office')).then((r) => r.json()), fetch(settlementApi('/tokens/m2')).then((r) => r.json()), fetch(exchangeApi('/health')).then((r) => r.json()), - fetch(settlementApi('/public/money-supply')).then((r) => (r.ok ? r.json() : null)), + fetch(loadOfficeMoneySupply()), ]); setOffice(o); setTokens(Array.isArray(t.tokens) ? t.tokens : []); diff --git a/services/settlement-middleware/src/api/routes/settlement.ts b/services/settlement-middleware/src/api/routes/settlement.ts index 0a6c243..6bd22ff 100644 --- a/services/settlement-middleware/src/api/routes/settlement.ts +++ b/services/settlement-middleware/src/api/routes/settlement.ts @@ -57,7 +57,7 @@ export function createSettlementRouter(): Router { const officeId = settlementOfficeId(); const profile = loadOfficeProfile(); - router.get('/health', (_req, res) => { + router.get('/health', async (req, res) => { let chainStats = { total: 0, active: 0 }; try { const reg = loadOmnlChainRegistry(); @@ -65,7 +65,7 @@ export function createSettlementRouter(): Router { } catch { /* optional */ } - res.json({ + const payload: Record = { service: 'omnl-settlement-middleware', status: 'ok', mode: process.env.SETTLEMENT_MIDDLEWARE_CONFIG?.includes('production') ? 'production' : 'standard', @@ -77,7 +77,38 @@ export function createSettlementRouter(): Router { name: profile.name, }, enforceSingleOffice: loadConfig().enforceSingleOffice ?? false, - }); + }; + const includeLedger = + req.query.ledger === '1' || + req.query.include === 'money-supply' || + req.query.include === 'ledger'; + if (includeLedger) { + const cfg = loadConfig(); + const allow = + cfg.production.onlineBankMode || process.env.OMNL_PUBLIC_MONEY_SUPPLY === '1'; + if (allow) { + try { + const [balances, fineractConnected] = await Promise.all([ + fetchGlBalances(officeId), + fineractOfficeReachable(officeId), + ]); + const snapshot = buildMoneySupplySnapshot(officeId, balances); + const hasActivity = Object.values(balances).some((v) => Math.abs(parseFloat(v) || 0) > 0); + payload.moneySupply = { + ...snapshot, + fineractConnected, + fineractLive: fineractConnected && hasActivity, + interoffice: { + dueFromHeadOffice: balances['1410'] ?? '0', + gl1410: balances['1410'] ?? '0', + }, + }; + } catch (e) { + payload.moneySupplyError = e instanceof Error ? e.message : String(e); + } + } + } + res.json(payload); }); router.get('/office', (_req, res) => {