The contracts
Five Soroban contracts, written in Rust. Three of them carry the deal. The other two feed it data.
| Contract | What it does |
|---|---|
note-token | One instance per class. Holds the notes, the holder registry and the day weights used to split coupons on transfer. |
abs-deal | The deal itself: the subscription escrow, the closing, the waterfall, the reserve, the carry. |
paying-agent | Receives each class aggregate and pushes stablecoin to every holder. |
rate-oracle | Publishes the EURIBOR 1M fixing on chain. |
asset-nft | The tokens describing the vehicles, batteries, obligors and the pool. |
note-token
A note token has zero decimals, so a note cannot be split. It has no burn function and no mint after issuance is finalized. There is no deposit, no withdrawal, no redeem and no price.
It keeps the list of holders so the paying agent can iterate it, and it keeps an accrual ledger for the coupon split. The ledger is lazy: a transfer freezes the seller's weight for the periods they slept through and starts the buyer's, in constant time, without walking the holder list.
abs-deal
This is the contract the deal lives in. Its states run Funding, Amortizing,
Enforced, Matured, with Aborted if the funding window fails.
During funding it escrows subscriptions and refunds cancellations. close()
performs the delivery versus payment: proceeds out, notes issued, reserve funded,
all in one transaction, with a balance assertion at the end.
After closing, distribute(period, collections) runs the waterfall described in
the priority of payments. The authoritative number is the
outstanding nominal per note. The note factor is derived from it, never stored
independently, so the two can never disagree.
paying-agent
The waterfall hands this contract each class aggregate, interest and principal together. It then pays holders.
push_batch is permissionless: anyone can call it, and it processes up to ten
holders per transaction with a cursor so it can be resumed. If a transfer fails,
for example because the recipient has no trustline, the amount is recorded as
claimable and the holder can take it whenever they want. Per holder, the contract
tracks interest and principal received separately.
rate-oracle
Class A pays a floating coupon, so the deal needs the EURIBOR 1M fixing. No third party publishes that fixing on Stellar. Reflector and RedStone publish crypto asset prices, not bank reference rates. So a relay signs the EMMI fixing into this contract, and the waterfall reads it at distribution time with a staleness check.
What the contracts check about themselves
Three invariants hold on chain, and a transaction that would break one fails:
- the deal contract's balance equals the reserve plus the carry
- the paying agent's balance equals the allocations plus the claimables plus the rounding dust
- stablecoin is conserved across a distribution: nothing is created, nothing disappears
Tests
62 tests across the workspace. They cover the arithmetic, not the plumbing: the per note rounding vector from a real prospectus (190.99 per note, 5,000 notes, 954,950.00 paid, 49.39 carried), the reserve release and refill cycle, the enforcement switch, the atomicity of closing, the coupon split on a mid period transfer, and the conservation of stablecoin.
cd contracts && cargo test --workspace
Addresses on the test network
Deal 1, amortizing:
| abs-deal | CB3S3NWG7IUKUBAWAAJPFKVMCIMTRJ73GHZX6YZASRMZPVUGYFLCATJ4 |
| Class A note | CBHFKNK7UK6YBVXZUWPOMY6LK44FZJSKWHPF4HJBUBV64KC455IJDROK |
| Class B note | CDRPAMGBJ6BSRQZE5M56DYCFZW7ODPFVCYLT4AA2OQGIUIDHPCTRBU3O |
| Class C note | CB3IK7HZQMZZG4GIYOEUPRUEIDUP54MIHXIBYLLAM4QUKHB7H7MYIOQJ |
| paying-agent | CAXBYHZVHXOP3HQCMXPPVZMDUYEO27CTQQQDMWVNMMGSRCBSJHGIARZW |
| rate-oracle | CAAOMPQADAW34FU4VUXDUHS6RDF6SVGCTK4S2T2YONIKNQA22IBYA72X |
Deal 2, open for subscription:
| abs-deal | CBVCKQH6CSGRS5W7SYZAJJ3MH5QUWNX7HKWTSLXK4YHPOSY3YZJ2I7AP |
| Class A note | CAXW4LVJEJL4A4S7WH5VZOMITJDUXFXIPYDRX7MJF64HLYO6X3JMNZEP |
| Class B note | CAXTFDN7ATWS4MJALVOLOWWQAAEOAIWGGKQ2N3XSQKEGKKDE6B7V7E6S |
| Class C note | CCCFVGMXJE2ZM22CP56BPQBO56I5PN5X4IB6Y2RFK2X2E2FNYLL4NEAF |
| paying-agent | CCD2G6GCWW77RKX3Y4JXUOSNPD7NUAH5Y46SLV64AVACUYR5HZT7E7N4 |
Settlement is in EURC, issued on Stellar by Circle. The test network contract is
CBEO2RDQKBM7S3TYOYKBWAJEC6WMYPCW6JJWX47UCLFMUJI2EUZPJOXW.