Verifying a Roll
Hash the file, read the registry, and compare the two.
What goes on chain
Every Roll file is hashed with SHA-256 over its exact bytes. Under the Roll's number, the operator writes three things to the RollRegistry contract: the hash, the closing price as navPerShare and the URL where the file is published. The contract adds the block timestamp. rolls(uint16 n) returns the four values as (bytes32 docHash, uint256 navPerShare, string uri, uint64 at), and latest() returns the number of the most recent Roll.
navPerShare is read from the vault at the moment of publication: convertToAssets(1e18) multiplied by 1,000,000. It has 12 decimals, and since the vault answers in whole USDG base units, only the first six carry information. The last six are zeros.
In the browser
Open /roll#verify. The page hashes the Roll file in your browser, reads rolls(n) from Robinhood Chain through the public RPC, and compares the two. No wallet is needed. You can also drop in a Roll file you downloaded earlier, and the page hashes that file instead.
From a terminal
To do the same by hand, hash the file and read the registry. cast is part of the Foundry toolkit. The address below is the live RollRegistry, listed on Chain and addresses.
sha256sum 001.csv
cast call 0xC4C3E3Ddf5a9E383a88cdbE481fF7CBE0ff98E73 "rolls(uint16)(bytes32,uint256,string,uint64)" 1 --rpc-url https://rpc.mainnet.chain.robinhood.com
On macOS, use shasum -a 256 in place of sha256sum. In Windows PowerShell, use Get-FileHash -Algorithm SHA256, which prints the hash in capitals. cast prints four values:
- The document hash, with a
0xprefix. The 64 hex characters after the prefix must equal the output ofsha256sum, ignoring case. navPerShare, the closing price as an integer with 12 decimals, so 1024472000000 means 1.024472 USDG. Compare its first six decimals withprice_closein the file. They can differ by 0.000001, because the vault's formula includes its virtual-share offset and the Roll's does not.- The URL where the operator published the file.
- The publication time as a Unix timestamp.
The contracts package has a script that runs the same comparison and prints MATCH or MISMATCH. Given a URL or a local path it hashes that file; given only the Roll number, it downloads the URL stored on chain. Set REGISTRY in the environment or in contracts/.env first.
cd contracts
REGISTRY=0xC4C3E3Ddf5a9E383a88cdbE481fF7CBE0ff98E73 npm run verify-roll -- 1 https://rentday.xyz/data/rolls/001.csv
Hash the file exactly as you downloaded it. Opening a Roll in a spreadsheet and saving it again can change line endings or quoting, and any changed byte produces a different hash.
Numbering and corrections
The registry is append-only. Roll numbers start at 1 and run in strict sequence: publish is owner-only and accepts n only if it equals latest() + 1, so a number cannot be skipped or reused. The contract has no function to update or delete a Roll. If a published Roll turns out to be wrong, the correction comes in a later Roll, and the original stays on chain beside it.
What a match proves
A match proves that the file you hold is byte for byte the file the operator committed, at the time the registry records. Nobody has edited it since, the operator included.
What a match does not prove
A matching hash proves the file is unchanged since it was committed. Whether its figures are true is a separate question, which you answer by opening the transactions the file names.
- That the figures are true. The operator could commit a file with false figures, and it would still match. Open each
claim_tx, theswap_txand thesettle_txon the explorer and compare the amounts with the file. - That the arithmetic is right. Check the identities on Reading a Roll.
- That the file is complete. A claim left out before committing would not show in the hash. The owner wallet's history on the explorer lists every claim it received, so you can compare the two.
Sample Rolls
The six sample Rolls, S1 to S6, are generated from illustrative fee data by the same close engine. They were never committed to the registry, so there is nothing on chain to compare them with. Hashing one still works, and gives the same result on every machine because the format is byte-stable.