CovenantBonds & CovenantBondVault
CovenantBonds
Every position is an ERC-721 token, so the storage is keyed by token id rather than by address. That is what lets one wallet hold several distinct positions, each with its own principal, rate and bonus clock.
| Field | Meaning |
|---|---|
principal | The basis rewards are computed on. Not a withdrawable balance. |
pending | Accrued and not yet claimed |
rateBps | Stored daily rate — base plus compound steps, 1000 (10%) to 2000 (20%). The commit boost is not stored here; it is applied live. |
origin | 0 = Sell, 1 = Commit. Permanent — it survives everything. |
ownedSince | When the position last changed hands |
boostDead | Sticky: once the boost is forfeited it never returns for that bond |
Entrypoints
openBond(amount)— voluntary, 20%..100% of the caller's balance, 15%/day effective at birth (the 10% base plus the +5 boost). Mints a new position.openBondFrom(owner, amount)— the sell-side retention, entry rate 10%/day, callable only by the wired retention sourcecompound(tokenId)— rollspendingintoprincipal; adds +0.25 point at most once per 6h. The effective rate never exceeds 20%/day.claim(tokenId)— pays out to the owner; the rate is untouchedmerge(tokenIds)— consolidates your positions into the first one; every bond merged must share the same origin and the same boost statetokensOf(address)— lists a holder's positions, so the app needs no indexer
Views worth knowing
rateOf(tokenId)— the stored rate: base plus compound stepseffectiveRateOf(tokenId)— the stored rate plus the live boost, capped at 20%/day — the number a holder actually earnsexemptAllowanceOf(address)— retention-free selling volume left:5 x commitPrincipalOfminusexemptUsedOf, floored at zero. The figure that prices a sale: the hook waives the retention only while it covers the whole amountcommitPrincipalOf(address)— sum of the wallet's commit-origin principals, the base of the allowance. Grows onopenBondand on every compound of a commit bondexemptUsedOf(address)— exempt volume consumed, lifetime. The hook adds to it throughconsumeExemption(seller, amount), which only the wired retention source may calldebitedThisTx(address)— how much CVN the wallet has sent out so far in the current transaction. Zero at the start of every transaction, and spent byconsumeExemption, so it proves a seller is really selling on a route the hook cannot otherwise vouch forhasCommitBond(address)— true while the wallet owns at least one commit-origin bond (display-level; the allowance is what decides)commitBondCountOf(address)— how many commit-origin bonds the wallet holdslastStripAt(address)— the instant the wallet last moved tokens out
EXEMPT_CAP_MULTIPLE is the constant behind the allowance: 5.
The token contract reports every outbound transfer to CovenantBonds — the wallet and
the amount (onTokenDebit, wired once via initBonds), which is what strips the boost
and what feeds the same-transaction tally; zero-amount transfers and self-transfers are
ignored, so nobody can strip a stranger with a 0-amount transferFrom. tokenURI is fully on-chain
and lists each position's principal, origin, whether its boost is active, and the
effective daily rate.
CovenantBondVault
Cold storage. It can do exactly one thing: send a fixed tranche to the distributor.
setDistributor(address) → correctable
freezeDistributor() → irreversible
releaseTranche() → possible ONLY after the freeze
The guarantee
releaseTranche reverts while the destination is still changeable. Setting a destination
and moving value are therefore mutually exclusive states, and anyone can check which
one holds:
- the address is still editable → the vault cannot move a single token; or
- tokens can move → the address is already permanent.
That closes the window a plain "setter now, renounce later" pattern would leave open, during which an operator could point the vault at their own wallet. The destination must also be a contract, so a mistyped wallet address cannot become it.
The operator controls when. Never where.