Live at por.worldlibertyfinancial.com
A real-time dashboard that reads USD1 stablecoin reserve data from a Chainlink oracle on Ethereum and tracks USD1 total supply across ten chains — five native (Ethereum, BNB Chain, Tron, Solana, Aptos) and five bridged (Plume, AB Core, Monad, Mantle, Morph). All data is sourced on-chain — no backend, no API keys required.
- Live reserves data, posted to Ethereum mainnet every 10 mins
- On-chain data via Chainlink oracle (
latestBundle()+bundleDecimals()) - Multi-chain USD1 supply tracking across 10 chains (5 native + 5 bridged)
- CCIP pool balance tracking (locked tokens on Ethereum, BSC, Solana, Aptos)
- Collateralization ratio computed from on-chain reserves vs. total supply
- Per-chain supply breakdown with token addresses, copy-to-clipboard, and block explorer links
- Responsive table UI with sortable columns (desktop) and card layout (mobile)
- The page auto refreshes every 60 seconds + manual refresh
- Contract details with copyable oracle address and Etherscan link
- Dark/light theme toggle (defaults to dark)
- Optional Google Analytics with cookie consent banner (Accept / Reject) plus DNT / GPC opt-out
- No API keys or backend required — uses public RPCs (with optional custom RPC endpoints for all 10 chains)
| Category | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| Language | TypeScript 5.9 |
| Web3 (EVM) | wagmi 3 + viem 2 (contract reads via useReadContracts multicall) |
| Web3 (non-EVM) | @aptos-labs/ts-sdk, @solana/kit, tronweb |
| State | React Query + Jotai (custom RPCs persisted in localStorage) |
| UI | @tanstack/react-table (sortable columns, responsive layout) |
| Styling | Tailwind CSS 4 + shadcn/ui (Radix Nova) |
| Linting | Biome 2 |
| Git hooks | Lefthook + Commitlint (conventional commits) |
- Node.js 24+ (see
.nvmrc) - pnpm 10+
git clone https://github.com/worldliberty/cre-por-dashboard.git
cd cre-por-dashboard
pnpm install
pnpm dev| Script | Description |
|---|---|
pnpm dev |
Start dev server with Turbopack |
pnpm build |
Production build |
pnpm start |
Start production server |
pnpm lint |
Run Biome linter |
pnpm lint:fix |
Auto-fix lint/format issues |
pnpm typecheck |
TypeScript type checking |
pnpm clean |
Remove build artifacts and node_modules |
├── app/ # Next.js App Router
│ ├── layout.tsx # Root layout (fonts, providers, preconnects)
│ ├── page.tsx # Home page → PorDashboard
│ ├── error.tsx # Error boundary
│ ├── not-found.tsx # 404 page
│ └── globals.css # Tailwind + design tokens
├── components/
│ ├── por/ # Dashboard components
│ │ ├── dashboard.tsx # Main orchestrator (fetches data, composes sections)
│ │ ├── header.tsx # Logo, title, Live badge, theme toggle
│ │ ├── hero.tsx # Large reserves display
│ │ ├── stats-grid.tsx # Collateralization ratio + total supply cards
│ │ ├── contract-details.tsx # Data source, oracle address, raw details
│ │ ├── supply-table/ # Per-chain USD1 supply breakdown
│ │ │ ├── details.tsx # Main wrapper (card, footer, raw total supply)
│ │ │ ├── desktop-table.tsx # Table layout (desktop)
│ │ │ ├── columns.tsx # Column definitions (@tanstack/react-table)
│ │ │ ├── cells.tsx # Reusable cell renderers
│ │ │ ├── mobile-layout.tsx # Card layout (mobile)
│ │ │ └── mobile-chain-item.tsx # Mobile card item
│ │ ├── cookie-consent.tsx # Cookie consent banner
│ │ ├── warning-banner.tsx # Supply warning banner
│ │ ├── refresh-button.tsx # Extracted refresh button
│ │ ├── rpc-settings-dialog.tsx # Custom RPC settings dialog
│ │ └── footer.tsx # Data source disclaimer
│ ├── primitives/ # Reusable display components
│ │ └── formatted-number.tsx # Number formatting
│ ├── providers/ # React context providers
│ │ ├── store.tsx # Jotai StoreProvider
│ │ ├── theme.tsx # next-themes ThemeProvider
│ │ └── wagmi.tsx # WagmiProvider + QueryClientProvider
│ └── ui/ # shadcn/ui component library (+ table.tsx)
├── hooks/
│ ├── use-por-data.ts # Reads Chainlink oracle, decodes bundle, returns POR data
│ └── use-usd1-supply.ts # Aggregates USD1 supply across all 10 chains
├── lib/
│ ├── analytics/ # Google Analytics (privacy-first)
│ │ ├── analytics.tsx # GA script loader + consent management
│ │ └── page-view.tsx # Page-view tracker component
│ ├── config/
│ │ ├── site.ts # Site metadata
│ │ └── client.ts # Client-side env vars
│ ├── contracts/
│ │ ├── por-oracle.ts # Oracle address, ABI, constants
│ │ └── usd1-token.ts # USD1 addresses, chain metadata, explorer URLs
│ ├── fetchers/ # Non-EVM supply fetchers (Tron, Solana, Aptos)
│ ├── schemas/rpc.ts # Zod schemas for RPC URL validation
│ ├── store/
│ │ ├── index.ts # Jotai store
│ │ ├── rpc.ts # Custom RPCs atom with localStorage persistence
│ │ └── analytics.ts # Analytics tracking atoms
│ ├── utils/
│ │ ├── format.ts # Address truncation + number formatting helpers
│ │ └── privacy.ts # DNT / GPC opt-out detection
│ ├── wagmi.ts # Wagmi config (7 EVM chains, public RPCs with fallback)
│ └── utils.ts # cn() classname utility
├── public/chains/ # Chain logo SVGs (10 chains)
├── types/
│ └── gtag.d.ts # Google Analytics type declarations
- The app connects to Ethereum mainnet via public RPCs (no wallet needed)
useReadContracts(wagmi) multicallslatestBundle()andbundleDecimals()on the Chainlink oracle at0x691b...d4c4latestBundle()returnsbyteswhich isabi.encode(uint256 timestamp, uint256 reserves)— decoded with viem'sdecodeAbiParameters- Reserves are divided by
10^decimals(18) for the human-readable USD amount - RPC data auto-refreshes every 60 seconds; block number updates in real-time via
useBlockNumber({ watch: true })
Native chains (USD1 minted directly):
- Ethereum & BNB Chain — ERC-20
totalSupply()via wagmiuseReadContractsmulticall (viemerc20Abi) - Tron —
totalSupply()contract call viatronwebwith RPC fallback (TronGrid → TronStack) - Solana —
getTokenSupplyon the USD1 mint via@solana/kitwith RPC fallback (PublicNode → Ankr) - Aptos —
getFungibleAssetMetadataByAssetTypevia@aptos-labs/ts-sdk(mainnet, readssupply_v2)
Bridged chains (USD1 bridged via CCIP):
5. Plume, AB Core, Monad, Mantle, Morph — ERC-20 totalSupply() on the bridged USD1 address (0x1111...db61) via wagmi multicall
CCIP Pool balances:
- Ethereum & BSC — ERC-20
balanceOf(poolAddress)via wagmi multicall - Solana & Aptos — fetched via their respective non-EVM fetchers
Non-EVM fetchers run as @tanstack/react-query queries. The raw total supply displayed in the table footer normalizes per-chain bigint values to 18 decimals before summing (to avoid precision loss from mixed decimals). The collateralization ratio uses the human-readable total supply (reserves / total supply).
All data auto-refreshes every 60 seconds; block number updates in real-time via useBlockNumber({ watch: true }).
The app uses public CORS-friendly RPCs with automatic fallback for each chain. No API keys needed.
You can add your own RPC URLs per chain via the Settings (gear icon) button in the header:
- Click the gear icon → "RPC Settings"
- Add one or more URLs for any chain (all 10 chains supported)
- Click Save
Custom endpoints are tried first, before falling back to the built-in defaults. Settings are validated (must be http(s) URLs) and persisted in localStorage.
| Chain | Endpoints |
|---|---|
| Ethereum | Ankr, PublicNode, DRPC, 1RPC |
| BNB Chain | Ankr, PublicNode, Binance, 1RPC |
| Tron | TronGrid, TronStack |
| Solana | PublicNode, Ankr |
| Aptos | Aptos SDK default (mainnet) |
| Plume | rpc.plume.org |
| AB Core | rpc.core.ab.org |
| Monad | rpc.monad.xyz |
| Mantle | rpc.mantle.xyz |
| Morph | rpc.morphl2.io |
Copy .env.example to .env.local for optional configuration:
| Variable | Description |
|---|---|
NEXT_PUBLIC_GOOGLE_ID |
Google Analytics measurement ID (e.g. G-XXXXXXXXXX). Analytics are disabled when unset. Shows cookie consent banner. Also respects DNT / GPC. |
This software is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
The entity posting this code shall not be held liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort arising in any way out of the use of this software, even if advised of the possibility of such damage.
The contents of this repository are for informational and educational purposes only. Nothing contained herein constitutes professional advice. Use of this code is at your own risk.
This project is licensed under the MIT License - see the LICENSE file for details.