George Sarris (0xcircuitbreaker) · · 10 min read
Annuities On-Chain: How Lucrum's Annuitas Module Works
Annuitas is a later-phase Lucrum annuity specification with three proposed tiers, deferred accumulation, and an inactivity-triggered beneficiary mechanism.
In this article
Status note
Annuitas is a later-phase Lucrum module. This post describes behavior in the March 2026 specification; it does not establish a production deployment, an independent audit, regulatory approval, insurance coverage, or historical returns. V2 ideas — Guard coverage, dynamic premiums, multi-asset annuities, NFT receipts, and a secondary market — are roadmap items.
What is an annuity, minus the jargon
An annuity is a contract: you hand over a lump sum of capital, and in exchange you receive a stream of payments over time. The counterparty manages the capital so the stream is delivered. Payments can be fixed in amount, variable with market performance, or floored at a guaranteed minimum — each variant corresponds to how the counterparty structured the risk.
Annuities are an established traditional-finance primitive. Annuitas explores how some cash-flow rules might be expressed in smart contracts. That changes the risk model rather than removing it: contract bugs, strategy losses, governance, liquidity, custody, and legal treatment all require separate evaluation.
The three V1 tiers
Variable Annuity
Intended payment = yield attributed to this annuity for the period. The payment formula does not intentionally draw principal. If attributed yield is zero, the payment is zero; however, the current multi-annuity harvest-attribution gap described below must be fixed before this behavior can be relied on across shared routers.
- Intended use: scheduled distribution of strategy yield without a designed principal drawdown
- Risk: payment amounts fluctuate with market conditions
- Principal: not intentionally drawn by the payment formula; still exposed to contract and strategy losses
Fixed-Term Annuity
Payment = target amount per period, principal amortized. You specify a target payment. The protocol funds each payment from a three-step waterfall:
- Yield earned this period
- Buffer reserve (accumulated surplus from prior periods when yield > target)
- Principal drawdown (when yield + buffer fall short)
The annuity moves to DEPLETED when currentValue + bufferReserve reaches zero (principal is the immutable initial deposit; currentValue is the drawable balance that amortizes over time).
- Best for: predictable income; accepts principal depletion
- Risk: principal is consumed; annuity has a finite lifespan
- Principal: amortized over the annuity's term
Guaranteed Annuity
Payment = whatever yield, buffer, and principal can fund; minPayment is an accounting target. The V1 contract follows the Fixed-Term waterfall. If the resulting payment is below minPayment, it pays the lower available amount, adds the difference to guaranteedShortfall, and emits GuaranteedShortfall. The contract does not top the payment up to the minimum.
V1 behavior: the shortfall is tracked and emits a GuaranteedShortfall event but is not automatically covered. The Guard insurance pool integration is a V2 feature; V1 documents the shortfall so actuarial reserves can price forward and V2 can cover new shortfalls going forward.
V2 roadmap: the specification proposes drawing a shortfall from a Guard pool funded by a Tribunus-governed slice of protocol fees. That path is not implemented in V1. Its payout order, failure behavior, and solvency assumptions require implementation and review rather than being treated as a current guarantee.
- Intended use: exploration of a future floor-backed tier; V1 does not deliver a funded floor
- Risk (V1): shortfall tracked, not covered
- Risk (V2 proposal): Guard pool solvency, implementation, governance, and pricing risk
How it's built — singleton architecture
Every Annuitas annuity is a uint256 ID inside one singleton contract (same pattern as Uniswap V4 and Lucrum's own Fideicommissum). No per-annuity contract deployment. This can make cross-annuity accounting cheaper, but it also makes correct attribution between positions essential.
V1 does not mint an NFT receipt per annuity. NFT wrapping (and the secondary market that enables) is V2 roadmap.
Share accounting and the current yield-attribution gap
Each annuity's deployed assets and withdrawals are tracked with internal shares per yield strategy, using an ERC-4626-style calculation with a virtual share offset (VIRTUAL_SHARE_OFFSET = 1e6). The offset is intended to reduce first-depositor inflation manipulation; it is not, by itself, proof of complete isolation.
The current harvest path has a separate attribution problem: _harvestFromStrategies(annuityId) calls each snapshotted router's global harvest(asset) function and credits the full returned amount to the annuity that triggered the call. It does not apportion that harvest using _annuityShares. Share accounting therefore scopes withdrawals but does not currently establish per-annuity yield isolation. Multi-annuity use needs proportional harvest attribution plus adversarial tests and review before the yield figures can be relied on.
IYieldRouter adapters
The design provides three strategy slots behind the IYieldRouter interface (shared with Fideicommissum). The names below describe the intended routes; they are not evidence that production adapters are registered or deployed:
| Strategy | Router | Illustrative design range | Risk |
|---|---|---|---|
| Conservative | Creditum (lending) | 3–5% target | lower by design, not risk-free |
| Balanced | Fiscus (managed pools) | 5–8% target | moderate by design |
| Growth | FRS (revenue-share staking) | 8–12% target | higher by design |
These ranges are specification examples, not measured or promised yields.
Yield strategy presets
On creation, an annuity picks one of four allocation presets:
| Preset | Creditum | Fiscus | FRS |
|---|---|---|---|
| Conservative | 100% | 0% | 0% |
| Balanced | 50% | 30% | 20% |
| Growth | 30% | 50% | 20% |
| Custom fallback | 33.34% | 33.33% | 33.33% |
Router snapshot
The design snapshots router addresses at annuity creation time. That can reduce one governance-replacement risk, but it does not prevent a malicious or vulnerable snapshotted router, an implementation bug, or losses inside the selected strategy.
Payment frequencies
Four fixed intervals at V1:
| Frequency | Interval |
|---|---|
| Monthly | 30 days |
| Quarterly | 90 days |
| Semi-Annual | 180 days |
| Annual | 365 days |
The buffer reserve smooths volatility
For Fixed-Term and Guaranteed tiers, the buffer reserve absorbs yield shocks:
Period 1: yield = 500, target = 300 → payment = 300, buffer += 200
Period 2: yield = 100, target = 300 → payment = 300, buffer -= 200
Period 3: yield = 0, target = 300 → payment = 300, buffer = 0, principal -= 300
High-yield periods build the buffer; low-yield periods consume it. The buffer is the first line of defense before principal is touched.
Deferred accumulation and the current activation edge case
An annuity can be created with a future payoutStartTime. Until that timestamp, it sits in the ACCUMULATING state, but no keeper loop runs automatically:
- Yield compounds into
currentValueonly when an external caller successfully invokesharvestYieldbefore the payout start. The function then redeploys that harvested amount.principalremains the immutable initial-deposit field. - No payments are made; the annuitant cannot claim.
- State changes only when
claimPaymentorharvestYieldcalls the internal activation check after the timestamp.
The current activation path has an important edge case. claimPayment sets lastPaymentTime during activation and then checks whether a full payment interval has elapsed; that same transaction reverts as PaymentNotDue, rolling the activation back. A post-start harvestYield call can persist activation only when it actually harvests a nonzero amount; otherwise NothingToHarvest also reverts the transition. The contract therefore does not yet support a reliable autonomous “purchase today, retire later” flow without an activation fix and keeper/user-call design.
Inactivity benefit — the permissionless dead-man's-switch
Each annuity designates a beneficiary address and an inactivityTimeout period. The lastActivityTime is updated whenever the annuitant:
- Claims a payment (
claimPayment) - Records activity (
recordActivity) - Changes the payment destination (
setPaymentDestination)
If block.timestamp > lastActivityTime + inactivityTimeout:
- Anyone can call
triggerInactivityBenefit(annuityId)— fully permissionless - A final
harvestYieldruns, thencurrentValue + bufferReserve + freshly-harvestedare withdrawn from strategies - The total transfers to the designated
beneficiary - State transitions to
TERMINATED
This is an inactivity-triggered transfer mechanism, not proof of death or incapacity and not a substitute for a will, trust, beneficiary designation, tax advice, or probate law. A timeout can fire while an annuitant is alive but unable to record activity, so production use would need careful recovery and legal design.
Payment routing — annuities as composable cash flow
Payments default to the annuitant's wallet, but any address works via setPaymentDestination(annuityId, destination):
| Destination | Use case |
|---|---|
| Direct wallet | Standard income |
| Usura adapter | Requires integration logic that calls Usura's deposit function |
| Fideicommissum adapter | Requires a receiver/call path defined by that module |
| Any address | Charitable giving, DAO treasury, sub-account |
The V1 setter changes only the address that receives a raw ERC-20 safeTransfer. It does not call a destination protocol. In particular, current Usura expects a registered source to call depositYield(routeId, amount) and then pulls tokens with transferFrom; simply transferring tokens to the Usura address does not perform that operation. The whitepaper's example structures are therefore integration concepts that need adapters and tests:
- Annuity → Usura → Fiscus. Needs a registered adapter that receives or pulls the payment and invokes the correct Usura route.
- Annuity → Fideicommissum. Needs a destination-specific deposit or accounting call; a bare token transfer is not proof that a trust position was funded correctly.
- FRS → Annuity → Wallet. Needs an explicit creation/funding transaction because Annuitas does not pull an FRS distribution into a new position automatically.
Why on-chain annuities aren't just "DeFi in a costume"
Three areas where an on-chain design changes the operating model:
Contract transparency
Traditional annuity terms can be complex, and surrender charges, riders, fees, and withdrawal rules vary by product and jurisdiction. Buyers need to read the actual contract and applicable disclosure rather than assume a universal structure.
Annuitas specifies payment formulas and waterfall priorities in code that can be inspected. That can improve rule transparency, but readable source is not equivalent to safe execution: users would still need to verify deployed bytecode, upgrade authority, router behavior, tests, and audits.
Transparent accounting, with different risks
Traditional annuities expose buyers to insurer solvency and jurisdiction-specific protections. An on-chain design can make some balances and rules inspectable, but transparency does not ensure solvency or make complex strategy positions easy to value. Annuitas would add smart-contract, strategy, liquidity, governance, and key-management risks; the proposed V2 Guard pool is not equivalent to regulated insurance.
Additional intended safeguards and their limits:
- The specification intends to restrict Tribunus from withdrawing annuity funds, changing core parameters, or terminating positions. Tests and an audit would need to verify that property in a release candidate.
- The proposed pause scope blocks new creation while preserving existing claim paths. That is a design goal, not a guarantee that every failure mode leaves funds accessible.
- Limited direct oracle use in the core formula. The current payment calculation is denominated in the deposited asset and does not directly query a price oracle. That does not eliminate oracle or market-manipulation exposure in selected routers, swaps, asset valuations, or other composed modules; each integration needs its own review.
Composable cash flow
Some traditional annuities restrict early access or impose surrender charges, but the amount and duration vary substantially and some products do not use that structure. Changing a payment destination also depends on the issuer's process and applicable controls.
Annuitas can change the ERC-20 payment recipient in one transaction. A wallet or treasury can receive that transfer directly; protocols such as Usura or Fideicommissum need adapter logic that invokes their own deposit/accounting methods. V2 proposes NFT receipts and a secondary market, but neither is implemented in V1.
Integration with the rest of the Lucrum ecosystem
The whitepaper sketches several neighboring integrations, but the current contracts do not wire all of them together:
- Pensio has its own
PAYING_OUTstate and monthly claim path in the current contract; it neither imports nor calls Annuitas. Automatic conversion is a whitepaper concept, not current behavior. - Fiscus (managed pools) is a balanced-strategy backing route for annuity principal.
- Creditum (lending) is the conservative-strategy backing route.
- FRS pools (asset-class revenue shares) are the growth-strategy backing route; FRS pool yields can also fund annuity principal directly.
- Guard (insurance) is proposed to backstop the Guaranteed tier's minimum payment floor in V2.
- Administration can approve assets, register the three router slots, and pause new creation through
onlyOwnerfunctions. Those functions become DAO-controlled only if ownership is assigned accordingly. The preset allocations themselves are hard-coded in_getEffectiveAllocation; V1 has no setter for them. - Fideicommissum integration is conceptual until an explicit adapter or compatible deposit receiver is implemented in both directions.
- Usura integration needs a registered source and a call to
depositYield; a payment-destination address alone is insufficient.
When an Annuitas position makes sense
Honest framing of the three variants:
Variable Annuitas is most useful when:
- You want yield exposure but prefer scheduled disbursements over manual claiming
- You want to avoid any principal drawdown
- You're matching a liability that can tolerate payment-amount variance
Fixed-Term Annuitas is most useful when:
- You need known nominal cash flow for a specific future window
- You're matching a defined liability schedule (child's tuition, property purchase, runway)
- You accept that the target schedule is not a locked yield rate and remains dependent on strategy results and available capital
- You're comfortable with principal amortization over the annuity's lifespan
Guaranteed Annuitas is most useful when:
- You are evaluating the proposed V2 floor-backed design rather than treating V1 as a guaranteed-income product
- You understand that V1 records a payment gap but does not make the recipient whole
- You are willing to evaluate Guard solvency, pricing, governance, and implementation risk if the V2 path is built
The proposed trade-off is inspectable rules and composable routing in exchange for smart-contract and strategy risk without the protections automatically associated with a regulated annuity. Tax, securities, insurance, and estate treatment are jurisdiction-specific and require qualified advice.
What's next
- Lucrum Architecture — the full module map (FOLLIS, FRS, Vestibulum, Tribunus, the yield engine)
- Pensio: Retirement Planning On-Chain with Automatic Annuity Conversion — upcoming
- Fideicommissum: Irrevocable Trusts and the Annuitas Integration — upcoming
- Guard Insurance: The V2 Roadmap for Guaranteed Annuitas Coverage — upcoming
Or browse the Lucrum product page for current development status. The public source is the Lucrum monorepo; treat the whitepaper and this article as specifications until versioned contracts, tests, audits, and deployment addresses are published.