# How to verify the transparency numbers yourself

The page at https://bremo.tech/transparency publishes a few specific numbers
about how the 21,000,000 supply is currently split: how much the founder
treasury still holds, how much has left the treasury, and how many addresses
hold any BREMO. This guide shows you how to confirm each of those against
Ethereum mainnet on your own machine, so the dashboard is a claim you check, not
a claim you trust.

It is a companion to [VERIFY.md](VERIFY.md), which proves the total supply is
21,000,000 and fixed forever, and to [VERIFY-POOL.md](VERIFY-POOL.md), which
covers the market question. This document assumes the fixed-supply fact from
VERIFY.md and only verifies how that fixed supply is distributed today.

## Which numbers, and which chain

At the time of writing, the transparency page and the file it reads,
https://bremo.tech/holders.json, showed:

- treasury still held: 20,550,200 BREMO (97.858 percent)
- distributed out of the treasury: 449,800 BREMO (2.1419 percent)
- addresses holding BREMO: 299

Do not hardcode these. They change as the treasury distributes. Read whatever
the live page shows right now and compare it to what you read from the chain
below.

### Compare at the same block, or the comparison is not meaningful

Every figure above is a function of chain height, not of the clock. A balance is
whatever it was at a specific block, so "the page and the chain must agree" is
only a fair test if both are read at the same height. If a transfer lands between
the moment we published and the moment you check, an honest snapshot and an
honest chain read will disagree, and nothing is wrong.

So `holders.json` publishes the height it was read at:

- `block`: the Ethereum block these figures describe
- `blockTimestamp`: when that block was mined, or `null` if we could not fetch it
- `scannedFromBlock`: the first block of the `Transfer` scan, the contract
  creation block

To reproduce the numbers exactly rather than approximately, pin your queries to
the published `block` instead of reading at latest. Most tools take a block
argument directly, for example `cast call TOKEN "balanceOf(address)(uint256)"
DEPLOYER --block <block>`, or the third parameter of an `eth_call` JSON-RPC
request. Read at that height and the treasury and distributed figures must match
to the wei. Reading at latest should still land close, and any gap should be
explained by transfers that occurred after our snapshot, which you can see for
yourself in the token's `Transfer` log.

One caveat worth stating plainly: most free RPC endpoints only serve recent state
and will reject a historical `balanceOf` beyond roughly the last 128 blocks. If
your endpoint refuses the pinned read, that is an archive-node limit on your side,
not a discrepancy in ours. Read at latest and reconcile the difference against the
transfer log instead.

These figures describe the **Ethereum mainnet** BREMO deployment, the same one
covered in section 6 of VERIFY.md. Keep the two ledgers straight: the sovereign
chain (chain ID 48555) allocates its own 21,000,000 to the genesis treasury
`0x304C0F278a46Cd09720655851fE05569a128F704`, and that is a separate ledger. The
transparency percentages above are about the mainnet token and the mainnet
deployer wallet, not the genesis address.

## The addresses you need

- BREMO ERC-20 token (mainnet): `0x93CfAE1cfa7AAA1f7D4b8Af85697a600a8dAdC2C`
- Deployer / treasury wallet (mainnet): `0x2410A309d09b5887D281921aBc5316ff84A0D121`

Confirm the token address against the one printed on
https://bremo.tech/transparency and https://bremo.tech/trade before trusting any
balance you read. A different address is a different token.

## What each number actually means

The treasury and distributed figures are exact and fully checkable, because they
are just two on-chain balances and one subtraction:

- treasury held = `balanceOf(deployer)` on the BREMO token
- distributed = `totalSupply()` minus treasury held = 21,000,000 minus treasury held
- treasury percent = treasury held divided by 21,000,000, times 100
- distributed percent = 100 minus treasury percent

So if you can read one balance and the total supply, you can reproduce every
number in the first two rows exactly.

The holder count is different and you should understand why before you trust it.
There is no single on-chain call that returns "number of holders." A holder
count is derived by scanning the token's `Transfer` event log from deployment to
now and counting the addresses that end with a nonzero balance. That is what the
repository's own read-only script `chain/scripts/dispersion-tracker.js` does, and
what `chain/scripts/refresh-holders.sh` publishes into `holders.json`. It is an
honest count, but it is a computed count, not a primitive one, and reproducing it
requires scanning logs, which free endpoints often rate-limit or cap by block
range. Treat the treasury and distributed numbers as the ones you can confirm in
seconds, and the holder count as the one that takes a log scan.

There is a further limit worth stating, because it is the weakness of the method
rather than of the result. A `Transfer` scan starts somewhere. Ours starts at the
`scannedFromBlock` published in `holders.json`, the contract creation block. A
scan cannot prove from its own output that its starting point was early enough,
so re-running the same scan and getting the same answer confirms the arithmetic
and not the coverage. If an address held BREMO through activity the window never
saw, both the scan and any repeat of the scan would omit it identically. Method 4
below is the check that closes that hole, and it does so without scanning any
logs at all.

## Method 1: Etherscan, no tools required

1. Open the BREMO token on Etherscan:
   https://etherscan.io/address/0x93CfAE1cfa7AAA1f7D4b8Af85697a600a8dAdC2C#readContract
2. Read `totalSupply`. It must be `21000000000000000000000000`, i.e. 21,000,000
   with 18 decimals. This is the fixed supply from VERIFY.md.
3. Under Read Contract, call `balanceOf` with the deployer address
   `0x2410A309d09b5887D281921aBc5316ff84A0D121`. Divide the result by 10^18. That
   is the treasury held figure. It must match the treasury number on the
   transparency page.
4. Subtract the treasury held from 21,000,000. That is the distributed figure. It
   must match the distributed number on the page.
5. For the holder count, open the token's Holders tab. Etherscan's own holder
   total is an independent computation of the same thing `holders.json` reports
   and should be in the same neighbourhood. Exact agreement to the last address
   is not expected, because different tools count dust and zero balances slightly
   differently. A large discrepancy is what would be worth questioning.

## Method 2: A direct RPC call

This uses the same guarded pattern as VERIFY-POOL.md. The guard matters: free
public endpoints sometimes report a live contract as having no code (see the
trap described in [README.md](README.md)), and a balance read against a codeless
token is meaningless. Confirm the token has code before trusting any number.

```js
const { ethers } = require("ethers");
const provider = new ethers.JsonRpcProvider("https://ethereum-rpc.publicnode.com");
const BREMO    = "0x93CfAE1cfa7AAA1f7D4b8Af85697a600a8dAdC2C";
const DEPLOYER = "0x2410A309d09b5887D281921aBc5316ff84A0D121";

// Guard: a balance from a codeless token proves nothing. Bail if the endpoint
// cannot see the token's code, and use Etherscan or a better endpoint instead.
const code = await provider.getCode(BREMO);
if (code === "0x") {
  throw new Error(
    "This endpoint reports the BREMO token has no code. Its reads cannot be " +
    "trusted. Use Etherscan or a different endpoint."
  );
}

const token = new ethers.Contract(
  BREMO,
  [
    "function totalSupply() view returns (uint256)",
    "function balanceOf(address) view returns (uint256)",
    "function decimals() view returns (uint8)"
  ],
  provider
);

const decimals = await token.decimals();
const supply   = Number(ethers.formatUnits(await token.totalSupply(), decimals));
const treasury = Number(ethers.formatUnits(await token.balanceOf(DEPLOYER), decimals));

console.log("total supply:", supply);           // expect 21000000
console.log("treasury held:", treasury);         // compare to the page
console.log("distributed:", supply - treasury);  // compare to the page
console.log("treasury pct:", (treasury / supply) * 100);
```

If `total supply` is not 21,000,000, stop: that contradicts VERIFY.md and one of
the two is wrong. Otherwise the treasury, distributed, and percentage lines
should match the live transparency page. If they do not match, the page is stale
or wrong, and you should say so.

## Method 3: Reproduce the holder count

If you want to check the third number too, count holders from the `Transfer`
log the way the project's own script does. You need an endpoint that will serve
historical logs over the full range since deployment. Many free endpoints cap
`eth_getLogs` to a small block window, so this is the check most likely to force
you onto an archive-grade or paid endpoint, or onto Etherscan's Holders tab from
Method 1.

If that endpoint requirement is what stops you, skip to Method 4. It answers a
stronger question than this one and needs nothing but ordinary `balanceOf` calls,
which every free endpoint serves.

The reference implementation is already in this repository and is read-only:

    node chain/scripts/dispersion-tracker.js

It scans `Transfer` events for the BREMO token, tallies the balance of every
address that has ever received BREMO, and reports how many end with a nonzero
balance. That count is what `refresh-holders.sh` writes into the published
`holders.json` as `holdersOnchain`. Running it yourself against a full-history
endpoint should reproduce, within the dust-counting caveat above, the number the
page shows.

## Method 4: Prove the published holder list is complete, without a log scan

Methods 1 to 3 all check whether the numbers we published are arithmetically
right. None of them checks whether the list those numbers came from is missing
anybody. That is a different question, and it is the one that matters most,
because the concentration disclosure on the transparency page is computed from
the same holder list. A missing holder would make the published dispersion
picture wrong while every other check still passed.

The check rests on one invariant, which needs no trust and no log scan:

    sum of balanceOf(every published holder) + balanceOf(treasury) = totalSupply

Supply is conserved, so if the published addresses plus the treasury do not
account for all 21,000,000, then some address holds BREMO that the page does not
list. The shortfall tells you how much, and dropping addresses from the list
changes the shortfall by exactly their balances, so it localises the gap rather
than merely flagging one.

Every call involved is an ordinary `balanceOf`, so this runs on the same free
endpoints that refuse the Method 3 log scan. The cost is one call per published
address, which is a few hundred calls, not one heavy historical query.

The repository has a read-only implementation. It takes no keys and sends no
transactions:

    node chain/scripts/verify-holders-onchain.js https://bremo.tech/holders.json

Pass the live URL rather than a local path. Doing so verifies the file the public
actually receives, instead of a local copy that may never have been deployed.
It prints JSON and exits nonzero if any check fails. The load-bearing field is
`checks.published_holders_account_for_all_supply`, with `on_chain.unaccounted`
showing the shortfall in BREMO. Run against the live file at block 25622962, it
reported all five checks true and an unaccounted balance of exactly 0.

### Read the two failure modes correctly

An unaccounted balance above zero does not automatically mean the published data
was wrong when it was published. There are two causes and you should tell them
apart before drawing a conclusion:

1. **The scan missed a holder.** The event scan never saw an address that holds
   BREMO. The published file was incomplete when written. This is the fault the
   invariant exists to catch.
2. **BREMO moved after the snapshot.** A transfer to an address not previously in
   the list landed after `holders.json` was written. The file was correct when
   written and is now stale.

Distinguish them by comparing the `block` published in `holders.json` against the
block you read at, and by checking the token's `Transfer` log between the two.
This is the same-height caution from the earlier section again: the invariant is
evaluated at current chain state, while the file describes a past height. A
recent distribution can therefore produce a nonzero shortfall with nothing at all
wrong.

The script keeps this distinction visible. It reports a per-address difference
between the published balance and the live balance separately, as `drift`, and
calls it staleness rather than a fault, because a real transfer between refreshes
is not an error.

### What this check does not prove

State the limits, or the check gets read as proving more than it does.

- It does not verify the holder **count**. It verifies that the listed addresses
  account for all supply. `holders.json` publishes `holdersOnchain`, which counts
  every address with a balance including the treasury, and `holders`, which
  excludes the treasury and is the external-hands figure. Those are counting
  conventions, and the invariant is indifferent to them.
- It cannot detect a spurious entry with a zero balance. Such an entry adds
  nothing to the sum, so the invariant still holds.
- It says nothing about who controls an address. Distinct addresses are not
  evidence of distinct people, which is precisely why the concentration
  disclosure is published alongside the headline.

## A reminder on framing

Every number here is a fact about how a fixed supply is currently distributed,
nothing more. None of it is a price, a valuation, a target, or a promise about
the future. A treasury that holds most of the supply is disclosed plainly and is
not a claim about worth. The initial pool ratio, if and when a market opens, is a
starting ratio, not a valuation and not a guarantee. Verify the distribution, do
not trust it, and do not read value into it.
