The published file format
The exact bytes that get hashed, section by section, so you can parse or regenerate a Roll.
This is the canonical document — the bytes that are hashed and committed on chain. It is generated, never typed, so it is byte-stable: sections in a fixed order, rows sorted, every amount at full precision.
This describes the published Roll. The operator's input ledger is a different, internal format and is not part of this contract.
Every example below is a real excerpt of ROLL 005 as the close engine produces it, so the figures reconcile against each other.
Shape
Plain CSV, \n line endings, a trailing newline, UTF-8. A field containing a comma, a quote or a newline is double-quoted with "" escaping. Sections always appear in the order below, separated by one blank line, and a section with no rows still prints its header.
deed.roll.v1
roll,005
period,2026-07
published,2026-08-01
section,units
section,units
property,unit,rent_usdg,status
A,1A,1395.000000,PAID
B,2B,1650.000000,LATE
F,3F,1940.000000,VACANT
Every apartment in the portfolio, exactly once, sorted by property then unit. status is PAID, LATE or VACANT. rent_usdg is the lease of record, not the amount received.
section,arrears
section,arrears
property,unit,for_period,amount_usdg
D,3D,2026-06,2120.000000
Rent banked this period for an earlier one. for_period is strictly before the Roll's period. Zero or more rows.
section,expenses
section,expenses
line,amount_usdg
maintenance_routine,3980.000000
maintenance_capex,0.000000
property_taxes,4370.000000
insurance,1472.000000
property_management,2781.450000
management_fee,3989.055702
performance_fee,2713.155000
All seven lines, always, in this order, with zero written as 0.000000. A missing line and a zero line are different claims. The first two are what the operator spent; the other five are computed from the published rates in Fees, so each can be recomputed rather than accepted.
section,curve_tax
section,curve_tax
eth_claimed,usdg_received
2.6035,8830.150000
Exactly one row: the community token's curve tax, claimed in ETH and converted to USDG. 0,0.000000 when there was no sweep in the period. See Reading a Roll.
section,revaluation
section,revaluation
property,amount_usdg
D,40000.000000
Zero or more rows — none in ROLL 005; the row above is from ROLL 006. This section sits outside the reconciliation below on purpose. An appraisal moves no USDG, so it moves no share price; it appears because it resets what property taxes and insurance are charged on.
section,totals
section,totals
scheduled,41205.000000
due,39265.000000
collected,37615.000000
arrears,2120.000000
expenses_total,19305.660702
rent_net,20429.339298
curve_tax,8830.150000
net_flow,0.000000
usdg_prev,6382489.124291
usdg_held,6411748.613589
supply_prev,6300000.0000
supply,6300000.0000
nav_prev,1.013093
nav,1.017737
Money at six decimals, share counts at four, prices at six. scheduled is every lease in the portfolio; due excludes vacant units, which owe nothing.
Two identities, and both must hold:
usdg_held = usdg_prev + rent_net + curve_tax + net_flow
rent_net = collected + arrears − expenses_total
nav = (usdg_held − net_flow) ÷ supply_prev
Amounts
Every monetary figure is written to all six decimal places. Taxes, insurance and the management fee are monthly twelfths of yearly rates and land on fractions of a cent — rounded to two, the expense lines total a cent less than expenses_total and a reader checking the arithmetic finds a gap that is not really there. The document has to reconcile, so it carries the whole number.
All division truncates toward zero, so residual dust accrues to the vault rather than to any holder.
Generating it yourself
public/deed-core.js exports closeAll(data), canonicalCsv(roll) and sha256Hex(text). Those are the same functions behind the CSV download, the on-page verifier and the hash that gets published — not a second implementation that happens to agree. See Run it locally.