the wrapper registry
Every address the app shows, every route we build and every price we publish starts from one file in our repository: packages/registry/registry.yaml. The api serves the same data at GET /v1/registry. It lists every chain, every issuer and every wrapper we track, and for each one, where we read it. The code generates typed data from it and refuses to build if an entry doesn't validate. If the file is wrong, everything downstream is wrong, so we treat it as data with sources rather than configuration.
our verification rule#
An address goes in only if we read it from the issuer's own published list: an issuer API, a token list or a docs page that names the contract. That page goes in source, the date we checked goes in verifiedAt, and if reading the source takes a step (which page, which field), that goes in sourceNote.
If we can't find an issuer source, the address is TODO and verifiedAt is empty. The app shows that wrapper as unverified and won't route it. We don't fill a gap from a block explorer, a DEX listing or a token that happens to have the right name. A scam token with the right symbol is the most likely thing to find that way.
Where things stand today:
| chain | wrappers | unverified |
|---|---|---|
| solana | 40 | 0 |
| ethereum | 41 | 1 |
| base | 1 | 1 |
| bnb chain | 60 | 0 |
| robinhood chain | 31 | 0 |
| arbitrum | 39 | 19 |
| hyperevm (data only, not routed) | 17 | 0 |
| all | 229 | 21 |
All of the unverified entries are Dinari's. Dinari doesn't publish a token list we could find, so we've left them unverified rather than guess.
what each field means#
Each wrapper entry:
| field | what it holds |
|---|---|
stock | the underlying ticker, one of our 20 stocks |
issuer | who issues it; points at an issuer entry |
symbol | the symbol the token contract reports, exactly. we don't invent symbols |
chain | where it lives; points at a chain entry |
address | the solana mint or evm contract, or TODO |
decimals | the token's decimals, as the contract reports them |
venues | where the issuer says it trades |
source | the issuer page the address was checked against |
sourceNote | how to read that source, when it isn't obvious |
verifiedAt | when we checked; empty exactly when the address is TODO |
units | how one token relates to shares of the stock, and where to read the multiplier live |
Each issuer entry holds what's the same for all its wrappers: the issuing entity, the legal form in plain words, excluded and professional-only jurisdictions, the mint window (as text, and as a schedule the app can evaluate), the redemption path, a link to its terms, and its own source and verifiedAt.
units#
The units block is the newest part and the one that matters most for prices. model says how the token relates to shares:
| model | meaning |
|---|---|
token2022-scaled-ui | solana scaled ui amount: raw tokens times a multiplier on the mint |
erc8056-ui-multiplier | evm uiMultiplier(): raw tokens times a multiplier on the contract |
rebasing | balances already adjusted; one token is one share |
ondo-svalue | one token is sValue shares, from ondo's oracle |
plain | one token is one share, no multiplier |
multiplier says where to read it (which chain, contract and function), and the indexer reads every one live, at most a minute old, before converting any price.
proposing a correction#
Open a pull request against registry.yaml. In the description, link the issuer page that shows the right value. Then:
- Run
pnpm --filter @isomer/registry generateto rebuild the typed data. - Run
pnpm verify. It validates every entry, checks the generated file is current and runs the tests.
We check the source ourselves before merging. A correction without an issuer source stays open until one turns up.
The repository isn't public yet. Until it is, write to hello@isomer.finance with the wrapper, the value you think is wrong, and the issuer page that shows the right one. That's all we need.