Engine
Contracts, roles, invariants, the network choice and the testing status.
Solidity with OpenZeppelin v5, tested with Foundry. Payments are in USDC. No contract is upgradeable, and the shared ones hold no funds.
Contracts
| Contract | What it does |
|---|---|
ComplianceRegistry |
Allowlist: KYC expiry, professional flag, country, frozen flag. Blocked countries. |
NoteNFT |
One ERC-721 for all series; each token is a position with its shares. |
IncomeSeries |
One clone per series: terms, raise escrow, payments, disputes, fees, claims. |
SeriesFactory |
Creates series only within the guardrails and in allowlisted assets. |
| Income vault | Optional: splits the beneficiary's income at source. |
Voluntary transfers stay off until the admin opens them; then they need released payments for two different periods, a 30-day hold, an eligible receiver (professional where required) and an unfrozen sender.
Roles
Admin grants roles, blocks countries and opens transfers. Arranger creates series. Compliance officer keeps the allowlist. Servicer posts payments, hardship pauses and buyout quotes, and keeps a heartbeat. Backup servicer takes over after 60 days of silence. Trustee reverses pending batches, replaces the servicer, pauses, terminates and vetoes forced transfer requests. Transfer agent moves sanctioned positions to custody at once; a lost key, inheritance or court order needs 7 days' public notice, and the owner can cancel lost-key requests. Issuer receives the raise and pays buyouts. Treasury receives fees.
Invariants
totalGross <= capAmount; in consumer mode,pvPaid <= principal.- Claims never exceed released net, and each series holds enough for everything claimable or pending.
- No role can change terms or withdraw holders' money; only a forced transfer moves a position without its owner.
- A pause never blocks claims, refunds, releases or maturity, lapses after 14 days and cannot restart within 14 days of ending.
- A beneficiary's total share across live series stays at or below 25%.
Network
Arbitrum One for mainnet, Arbitrum Sepolia for the public testnet, chosen over Base. Notes live five to nine years: Arbitrum gives users an exit window before regular upgrades, Base does not, and Base's sequencer is run by a US exchange. Both have native USDC.
Residual risks: Security Council emergency upgrades, FSRA recognition of USDC on Arbitrum, and one fixed asset per series until a planned migration path is built.
Testing status
As of 23 September 2026: 305 tests pass with 100% line and branch coverage: unit and fuzz tests, ten invariants over 256 random runs, all 27 reference-model scenarios replayed on-chain, and an end-to-end run on a local chain. An independent Codex CLI review added 31 tests and led to four engine fixes; its other findings are kept by design and documented. Public testnet deployment follows.
Not audited yet. Two independent audits and a bug bounty come before mainnet.
Updated