Verify a treasury yourself
You never have to trust this interface. Everything BALLAST shows is computed from public on-chain data you can read yourself. Here is how to reproduce the backing figure from scratch.
1. Find the treasury
From a project page, take the project token address and read its immutable
treasury() value on the explorer, or resolve it from the BallastFactory
creation event. Confirm the treasury's projectToken() points back to the
same token — this two-way check defeats a spoofed treasury.
2. List what it holds
On the ProjectTreasury contract, read:
assets()— every asset the treasury has heldlockedBalance(asset)— permanently locked amountcreatorWithdrawable(asset)— amount the creator could withdraw
The amount that counts toward backing is lockedBalance + creatorWithdrawable.
Pending (proposed-but-not-accepted) deposits sit in escrow and are not counted.
3. Price each asset
For each asset, read its Chainlink feed:
(, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();
uint8 feedDecimals = feed.decimals(); // read it — do not assume 8
- Reject a zero or negative
answer. - Check
updatedAt. Off-hours the price rests with no new heartbeat — that is expected, not an error. Note the age; do not discard the price for being rested. - On an L2, check the Chainlink sequencer uptime feed first. During a sequencer outage feeds go stale while contracts still respond.
- Do not multiply by the token's
uiMultiplier(). The feed price already includes it; applying it again double-counts.
4. Do the arithmetic
value(asset) = balance × price ÷ 10^(assetDecimals + feedDecimals)
total value = Σ value(asset)
backing per token = total value ÷ (totalSupply ÷ 10^tokenDecimals)
Compare it to what the project page shows. They should match. If the chain and this interface ever disagree, the chain is the source of truth.
5. Watch for withdrawals
Read pendingWithdrawal() on the treasury to see any announced withdrawal — its
asset, amount, and unlock time — without asking anyone's permission. Because
only one withdrawal can be active at a time and the notice period is immutable, the
countdown you see is the real one.
Reproduce it in code
The BackingLens contract does all of the above in a
single batched call, and its source is verified on the explorer. You can call it
directly, or copy its logic — it is the same math described here.