Bondi v2: Composable, fungible, verifiable
Our first offering (v1) fully matured in June 2025 on Base. We paid the final coupon along the principal onchain, delivering a 9.98% APR. v1 remains backward-compatible: if you haven’t claimed yet, use https://app.bondifinance.io/bondiv1 (you can also inspect the distribution contract from the landing page’s Track Record section).
With that foundation proven—and no additional financial risk introduced—we rebuilt the distribution layer to make Bond Tokens truly crypto-native: composable, fungible, scalable, and regulation-friendly.

Why we upgraded (what v1 couldn’t scale)
v1 worked, but two things didn’t scale:
- Proceeds distribution: coupons relied on per-investor accounting, which doesn’t scale and isn’t set-verifiable onchain.
- Bond Token distribution: also used per-user state and loops.
In v2 we fixed both and unified everything under a single Distribution.sol. We also prepared for multichain: partner programs will fund user incentives for funding participation and seed secondary liquidity (we match with Bond Tokens), so we added incentive flows to Distribution.sol and designed a no-bridge accounting model to keep everything onchain and compliant.
The goal: a plain ERC-20 Bond Token that trades cleanly on DEXs and fits DeFi collateral —without sacrificing compliance. Product overview: https://docs.bondifinance.io/docs/product/bond-tokens
Post-funding: verifiability through Merkle, fungibility through snapshot, UX through relayer
- Snapshot at deposit. For each distribution (coupons and incentive), entitlements are fixed at the deposit-time snapshot preserving Bond Token fungibility preserved; later transfers don’t change who’s owed.
- Merkle commitment. We commit one Merkle root per distribution; anyone can independently rebuild the full set and verify onchain. Claims verify in O(log N); rounding always floors and dust is left. Spec:https://docs.bondifinance.io/docs/product/implementation-spec
- Relayer = push-style payouts. For KYC'ed wallets, our relayer calls
claimCouponForUser(user, couponId, amount, proof)(we pay gas); non-KYC holders who later complete KYC will manually back-claim on our UI viaclaimCoupon(...)for all pending coupons once. All coupons after KYC completion are automated. - Maturity order: UI claims the final coupon first, then calls
redeemPrincipal()(burn BT, receive principal back at bond's face value)
Bondi Distribution Design vs. Alternatives
| Method | How it works (tl;dr) | Snapshot / Entitlement basis (preserves fungibility) | Population cost (admin-side, onchain/offchain) | Claim gas (user, onchain) | Set-level verifiability (can anyone recompute & check completeness onchain?) | Pros | Cons | When it fits |
|---|---|---|---|---|---|---|---|---|
| Our v2: snapshot-at-deposit + Merkle root (with relayer auto-claim) | Detect deposit → reconstruct balances at deposit block offchain → build Merkle → store root; relayer submits claimCouponForUser | Deposit-time offchain snapshot | Offchain: O(N) compute only. Onchain: O(1) (store root) | O(log N) proof verify + one SSTORE (paid by Bondi via relayer in our UX) | Yes. One root commits the full set; anyone can rebuild per our spec | Gas-scalable, auditable, keeps ERC-20 lean**; strong composability, fungibility, and a DEX-friendly token | We own tree/proof tooling | Large N; you want auditability + great UX (relayer “push”) |
| Direct onchain mapping (full storage) | Admin writes entitlement[user] = amount per coupon | Same: deposit-time offchain snapshot | Onchain: O(N) writes per coupon (tx storm) | O(1) read + SSTORE | No. There is no set commitment; you cannot verify completeness against a committed root | Trivial claims; no proofs | Onchain storage bloat; does not remove the need for an offchain snapshot | Very small N; ultra-simple drops (this was Bondi v1; fixed in v2 with FPUSD + Merkle snapshots) |
| Admin push (batched transfers) | Admin/relayer sends payouts to each recipient (batch where gas allows) | Same: deposit-time offchain snapshot | Onchain: O(N) runtime per coupon (multiple tx; batching limits) | 0 for user | No. Only per-tx traces; no set commitment to audit | Zero user friction; instant payout | Ops/gas heavy; retries/partial failures; All its UX benefits are provided by our relayer anyway, plus we add onchain verifiability with Merkle | Controlled drops where pure “push” is fine |
| EIP-712 signed claims | Offchain computes amounts at deposit block → per-user signature (user, amount, couponId, block, nonce); user/relayer submits | Same: deposit-time offchain snapshot | Offchain: O(N) signatures; Onchain: tiny setup | Sig verify + SSTORE (often ≥ Merkle per claim at scale) | No. Claims are individually authorized; there’s no set-level commitment. You must include a nonce/couponId in the signed payload to prevent signature replays | No tree; flexible ops | Needs trusted signer key; weak set-level audit story; ops to issue/distribute sigs | Medium N; okay with signer trust; don’t need set-level auditability |
| Snapshot-token inheritance (ERC20Snapshot v4 or Votes-based in v5) | Token exposes historical balance at deposit; contract stores snapshotId/block + rate = depositAmount / totalSupplyAt; each claim = balanceAt * rate (pure onchain math) | Onchain snapshot at deposit (entitlement computed onchain) | Onchain: O(1) (store id+rate); no per-address writes | O(1) math | N/A. Set completeness root not needed: entitlement is computed onchain from snapshotId+rate | Cleanest claim path; no proofs; O(1) claims | Snapshot is OZ v4-only (vendoring/maintenance). In v5 you’d approximate via ERC20Votes, which adds checkpoint writes on every transfer → persistent gas overhead → degrades composability, fungibility, and a DEX-friendly token | Low-trade/governance-style tokens; not ideal for a widely traded bond token |
**“keeps ERC-20 lean” vs inheriting ERC20Snapshot/Votes : our Merkle design does not add checkpoint/snapshot machinery inside the token, avoiding transfer-time overhead. ERC20Snapshot (v4): negligible one-time overhead per account after each snapshot ~7k–10k gas once, then normal transfers until the next snapshot (≈ $0.006–$0.02 on Base at 0.2–0.5 gwei, assuming ETH ≈ $4,000). ERC20Votes (v5) with forced auto self-delegation (votes ≈ balances for everyone): ~65.6k gas added to every transfer, always ≈ $0.05–$0.13 on Base at 0.2–0.5 gwei (ETH ≈ $4,000). Not ideal for a composable and highly-tradable Bond Token.
After proceeds are funded into Distribution, we close the round: the Orchestrator captures the deposit-time snapshot, rebuilds balances per our public spec, constructs the Merkle tree, and finalizes a single root onchain. That root is the commitment everything hangs on. No one is paid until it exists.
After the Orchestrator finalizes a single Merkle root onchain, the relayer continuously sweeps finalised rounds. For KYC-verified wallets, it calls claimCouponForUser(user, couponId, amount, proof) ; we pay the gas. Holders who weren’t KYC’d can complete KYC and use the UI’s back-claim to call claimCoupon(...) across all pending couponIds once; from then on, every new coupon is paid automatically by the relayer.
Funding: FpUSD receipts and multichain without bridges
- Unified Distribution. One contract handles bond allocation, incentives, coupons, principal, with KYC gates where required.
- FpUSD receipts. Users deposit a local USD stablecoin and receive FpUSD on the same chain. When bonds are emitted, they burn FpUSD for Bond Tokens in O(1) via
claimBonds()—no per-user allocation loops. - Multichain accounting, zero bridging. Our Watcher mirrors accounting only across chains (assets never move). Emission and claims always happen on the chain you funded. This removes bridge risk and aligns with compliance.
- Operational redundancy. We run multiple providers (websocket + webhooks) with dedupe so event detection is resilient.
Security and no added financial risk
- Least-privilege roles. Across Watcher / Orchestrator / Relayer; services can delay UX but cannot move user funds.
- Assets never leave their chain; only accounting is mirrored.
- Deterministic public spec for snapshots/proofs; anyone can rebuild and verify distributions end-to-end onchain.
- Built on v1’s battle-tested foundations —we changed the scaling model, not the risk model.
Conclusion
Bondi v2 delivers a market-friendly multichain Bond Token that stays fungible and composable, with auditable distributions and push-style UX—transparent, onchain, and without bridge risk. Funding remains chain-local via FpUSD receipts; proceeds are Merkle-verified; KYC’d users get auto-payouts; everyone gets verifiability. If you’re a builder, auditor, or partner chain, our spec and diagrams make it straightforward to validate every step.
More from the blog.
All posts
The Reinvestment Vault: How coupons become more bonds
Coupons are the whole point of a bond and the one thing DeFi cannot handle. The Reinvestment Vault keeps the Bond Token a full bond underneath and puts a clean, compounding ERC-20 share on top:…

Introducing the Redemption Vault: From request to cash
A Bond Token keeps everything a bond does, so its exit has to handle everything a bond does. The Redemption Vault gathers exits of any size into one real bond sale through the regulated custody…

Introducing v3: Every change to the Bondi core, and why
Bondi v3 is built on the v2 contracts and closes the gap between a token that pays coupons and a bond: calls, amortizations, a supply that grows, fees taken onchain, proceeds that never pass through…