Skip to content

Close a bond with its final coupon; emit BondMatured - #275

Merged
Greaker merged 3 commits into
developmentfrom
feature/redeem-with-final-coupon
Sep 8, 2026
Merged

Greaker merged 3 commits into
developmentfrom
feature/redeem-with-final-coupon

Conversation

@Greaker

@Greaker Greaker commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • BondManager.payCoupon now closes the bond on the final period: each holder is settled once for coupon plus principal in WNOK through BondDvP (Redeem operation) and their units are burned; unsold units the manager holds are burned without payment; partition supply must reach zero; and BondMatured(isin, paymentCount, principalPaid, couponPaid, unsoldBurned) is emitted once. Interim coupons are unchanged for holders and skip manager-held units, which removes the treasury-held-units coupon deadlock by construction. BondManager.redeem and the AllCouponsPaid / BondRedemptionComplete events are removed.
  • Adds the plan folder docs/plans/redeem-with-final-coupon/ and ADR 0005 (Proposed), updates the contract docs and two NatSpec pages, and refreshes the nb-bond-api BondManager ABI artifact.
  • Not operator-safe on its own: the API still exposes POST /v1/bonds/{isin}/redemptions against a function that no longer exists, and the projection never reaches a terminal status until the API ingests BondMatured. The follow-up PR (Phases 2–5: API, UI, sandbox evidence, docs) must land before the sandbox is redeployed from development.

Test plan

  • cd contracts && forge fmt --check && forge build --sizes && bash ./check-verify-latest-mapping.sh && forge test — 25 suites, 394 tests (closure, incomplete holders, underfunded closure, unsold units, fuzz)
  • cd services/nb-bond-api && npm run lint && npm run format:check && npm test && npm run build — 245 tests (ABI artifact only)
  • python3 scripts/verification/check-public-repo-hygiene.py && python3 scripts/verification/check-markdown-links.py
  • Slither via Contracts CI (not runnable locally on arm64)
  • Fresh local sandbox lifecycle (fully and partially allocated bond) is Phase 4, in the next slice

Add docs/plans/redeem-with-final-coupon/ (intent, design, plan, progress)
and ADR 0005 (Proposed): the final payCoupon pays coupon plus principal in
wNOK, burns every unit, skips and then burns unsold manager-held units
without cash, and emits one BondMatured event with totals; the separate
BondManager.redeem, its API route, the unused UI client, and the
AllCouponsPaid / BondRedemptionComplete events are removed. Index both in
the documentation index and the ADR index. No code changed.
Phase 0 of docs/plans/redeem-with-final-coupon/: the coupon test pins the
per-unit coupon at 42 WNOK (1000 nominal at 4.25%, integer-truncated) so
the closure change cannot alter interim payouts unnoticed, and the plan's
progress file records that ingestion applies a block batch manager-first
inside one database transaction, which the order-independent reducer
tolerates.
The final payCoupon now pays each holder coupon plus principal in one DvP
settlement with the Redeem operation, burns their units, burns any unsold
units the manager holds without payment, requires partition supply to
reach zero, and emits BondMatured(isin, paymentCount, principalPaid,
couponPaid, unsoldBurned) exactly once. Interim periods are unchanged for
holders and skip manager-held units, which closes the treasury-held-units
coupon deadlock by construction. The separate redeem entry point and the
AllCouponsPaid and BondRedemptionComplete events are removed.

The holder loop moves into _payHolders/_payHolder with Period and
PayoutTotals memory structs; keeping it inline exceeded solc's stack even
under via-IR. Tests replace the redeem cases with closure, incomplete
holders, underfunded closure, unsold units, and fuzz coverage: forge test
25 suites, 394 passed. Contract docs and the two affected NatSpec pages
describe the closure; the nb-bond-api ABI artifact is refreshed (API and
UI follow in the next slice). Plan progress in
docs/plans/redeem-with-final-coupon/progress.md; decision in ADR 0005.
@Greaker
Greaker merged commit 600b16b into development Sep 8, 2026
9 checks passed
@Greaker
Greaker deleted the feature/redeem-with-final-coupon branch September 8, 2026 14:55
Greaker added a commit that referenced this pull request Sep 8, 2026
Move docs/plans/redeem-with-final-coupon/ to docs/plans/archive/ with its
status set to Implemented (shipped via #275 and #276), tick its done
criteria, close out progress.md, and move the documentation-index entry
to the archive list. ADR 0005 moves to Accepted in the ADR index and the
documentation index. The contracts versioning note no longer names the
removed BondManager.redeem entry point.
@Greaker Greaker mentioned this pull request Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant