fix: scan all snapshots for oldest timestamp in fetchAllWalletData

snapshotsToDaily returns results sorted newest-first, so allSnaps[0] was
the newest timestamp. This caused fetchPrices to compute a near-zero date
range, resulting in $0 values for all but the most recent rows.

Also removed redundant refreshPrices() call from init flow (fetchAllWalletData
already fetches full-range prices). Added table data flow doc to AGENTS.md.
This commit is contained in:
Dione
2026-06-10 19:52:11 +00:00
parent b659d26ad1
commit e28e66b29f
2 changed files with 23 additions and 3 deletions

View File

@ -104,6 +104,22 @@ Cross-tab leader election uses `BroadcastChannel("dione_shared_stream")` with a
- Adding chart data? Update the embedded arrays (`walletCumulData`, etc.) — they are plain JS arrays of `[timestampMs, value]` pairs.
- `wallets.js` always forces `isVerified: false` on `loadWallets()` — persisted signatures are discarded. Verification must go through `WalletVerifier`.
## Transaction Ledger Table — Data Flow
How the table gets its rows and values:
1. **Fetch:** `fetchAllWalletData()``fetchWalletAaveData(address)` hits `/api/v1/portfolio/{address}/base/aave`, returns array of snapshot events.
2. **Deduplicate:** `snapshotsToDaily(events)` collapses events to one per day (keeps latest `block_timestamp` per day). **Result is sorted newest-first.**
3. **Store:** Deduplicated snapshots land in `addressSnapshots[address]`.
4. **Prices:** `fetchPrices(symbols, oldestDateMs)` fetches `/api/v1/prices/{symbol}/history?range=N` where N = days between now and oldest snapshot. **Critical:** you must scan all snapshots for the *lowest* `block_timestamp` to compute the correct range. `snapshots[0]` is the *newest* — never assume the array is oldest-first. The `aavePriceMap` is keyed `[priceSymbol][dateStr] = closePrice`.
5. **Render:** `renderCombinedTable()` iterates `addressSnapshots`, computes row values:
- `getTokenAmount(raw, symbol)` divides by token decimals (cbBTC /1e8, WETH /1e18, USDC /1e6)
- `priceForToken(symbol, dateStr)` looks up `aavePriceMap` for the matching date (falls back to nearest prior date)
- Each row shows USD = `amount × price` for wallet (cold), collateral, and debt columns
6. **Filter:** `updateDashboard()` hides/shows rows based on wallet-type and ledger-wallet checkbox filters.
If table rows show `$0` for non-recent dates, check that `aavePriceMap` covers the full historical range — the `fetchPrices()` call must use the *oldest* snapshot timestamp, not the newest.
## Coding Guidelines
You are an expert senior Web3 frontend engineer specializing in high-scale performance and stateless cryptographic security.

View File

@ -1490,7 +1490,12 @@ async function fetchAllWalletData() {
await Promise.all(promises);
const allSnaps = Object.values(addressSnapshots).flat();
if (allSnaps.length > 0) {
const oldestTs = new Date(allSnaps[0].block_timestamp).getTime();
/* snapshots are sorted newest-first; find the oldest */
let oldestTs = Infinity;
allSnaps.forEach(s => {
const t = new Date(s.block_timestamp).getTime();
if (t < oldestTs) oldestTs = t;
});
await fetchPrices(Object.keys(TOKENS), oldestTs);
}
}
@ -1801,10 +1806,9 @@ async function initDashboardGrid() {
const rawPrices = result.result.XXBTZUSD;
btcPriceData = rawPrices.map(item => [item[0] * 1000, parseFloat(item[4])]);
/* Fetch data for all verified wallets */
/* Fetch data for all verified wallets (already fetches full-range prices) */
await fetchAllWalletData();
await refreshPrices();
renderCombinedTable();
const cutoff = getOldestTransactionDate();