Lending
bivium-lending is the stack's first product: no-liquidation, fixed-term credit, built as a configuration of the series rather than as a protocol of its own. Lifecycle follows a loan through time; this page is the contracts and the decisions behind them.
The mapping
A lending market is a set of terms, and LendingSeries is the whole translation:
| Term | Series field |
|---|---|
| collateral | lockedAsset |
| loan token | strikeAsset |
| debt D per whole unit of collateral | ratio = D · 1e36 / 10^collateralDecimals |
| maturity | mintEnd and exerciseEnd |
| — | exerciseStart = 0, so it is repayable from the moment it exists |
That is the product. The borrower locks collateral, keeps the long — the right to repay D and take the collateral back — and sells the short, which is the lender's credit. Debt face rounds up, as the core charges it.
The economic claim the repository makes for this: instead of a borrower paying a path-dependent liquidation cost, the lender bears a hedgeable European put, and the surplus is redistributed between borrower, lender or market maker, and protocol. Whether the lender actually hedges it is the subject of Curator.
Which leg is sold makes the product
Minting creates a long and a short together, and holding both changes nothing: the pair burns back into the A it locked, so whoever holds both is simply still holding A. The economic event is selling one of the two legs, and the same mint gives a different product depending on which leg is sold:
| Sells | Keeps | Receives | Ends up with | |
|---|---|---|---|---|
| covered-call writer | the long, to a call buyer | the short | the premium C | the strike K if exercised, A back if not |
| borrower | the short, to a lender | the long | the loan p | the right to repay D and take A back |
Long and short together are A, so C + p = A: the loan a borrower can raise is the collateral's
value less the call it keeps, p = A − C(D). A higher D makes that call cheaper and the loan larger,
and makes the debt larger too. LTV and rate trade off along this one line. The lending market is
therefore the market for shorts. A lender's bid is a bid for the short (buy, not long), the relayer
takes only short offers on a lending market, and the lender's position is a transferable token.
What each side holds
The loan is non-recourse: a borrower who does not repay loses the collateral and owes nothing more. That is what makes it an option rather than a debt.
- The borrower holds the loan in cash and a call on its own collateral struck at D. Above D it repays and keeps the gain. Below D it walks away, and its loss stops at the collateral.
- The lender receives
min(A, D)at maturity, which isD − put(D). That is a risk-free D less a put struck at the debt. By put–call parityp = PV(D) − P = A − C, so the rate is the price of that put, and the credit risk is that put. It is why the Earn pool buys puts (Curator).
Repay-any-time costs the lender almost nothing
A fixed-rate, non-recourse loan that cannot be repaid early is a European option. Opening the window
at once (exerciseStart = 0) makes it American, and here that is worth almost nothing in money. Repaying
is exercising, so it pays the full face D whenever it happens: there is no interest rebate. Paying D early
only gives up the yield on D, and the collateral earns nothing by coming back sooner. That is the textbook
case of an American call on a non-yielding asset being worth the same as the European one. The lender's put
pays only at maturity in either case.
So the default costs the lender nothing it could price. What it buys the borrower is not money but its collateral back early: to sell it, to reclaim a vault to its own key, or to refinance. This is not a mortgage-style prepayment right, which is valuable because it cancels the remaining interest.
The window matters when someone else holds an exercise right over the borrower's collateral. That is the case with a call sold on the loan, next.
A collar sells the upside, not the long
Selling both legs would just be selling A. A collar sells the short as usual, which is the loan, and then sells a call on the long rather than the long itself. That gives away only the upside above K, and keeps the gain between D and K and the right to repay.
On an ordinary market the long (L1) is itself a token, so the call is a nested series that locks it
(OptionSeries.collarCall in bivium-option). It is struck at K − D in the loan token, and its window
must end before the loan matures (the core enforces NEST_GAP). The frontend and mm use the window maturity − 3 days to
maturity − 2 days. The borrower locks L1, sells the nested long to the buyer for a premium, and keeps the
nested short. If the buyer exercises, it pays K − D for L1 and then repays D for A, so it pays K in all.
The borrower's nested short collects K − D. If the buyer does not exercise, the nested short takes L1 back.
| At maturity | Outcome | Borrower ends with |
|---|---|---|
| A below D | no repayment; A goes to the lender | the loan and the premium |
| between D and K | repays D, keeps A | the gain above D, plus the premium |
| above K | called away | K − D, plus the premium |
The floor comes from the non-recourse loan, an implicit put at D. The cap comes from the call sold at K.
The premium lowers the cost of borrowing. Because a third party now holds an exercise right that would end
the loan, a European window is the safe default here: an American one would let the buyer take the
collateral at any spike. The buyers price and hedge on Deribit, whose options are European, so early
exercise gains them nothing. On a TBV market the long belongs to the app, so the same collar is a
TbvCallBook record rather than a nested series (Lifecycle). On
exercise the app repays the loan out of the strike and pays the borrower the rest.
While the call is open the borrower holds the nested short, not L1, so the loan cannot be repaid as it
stands. Repaying early means buying the call back: any long of the same nested series will do, since
burnPair burns a long with the matching short and returns what they lock — here L1 — after which
the loan repays as usual. Nothing in the core or bivium-option is added for this; it is three
ordinary calls, Exchange.fill on an ask for the call, Core.burnPair, and Router.exercise. What
makes it usable is a seller: the market maker that bought the call offers it back
(Lifecycle). A TBV collar has no such path: its call is a TbvCallBook
record, and a collared group cannot be repaid until the call ends.
Who takes the other side
A borrower trades with liquidity providers, not with other borrowers. Each of its actions has a counterparty the stack runs:
| Borrower | Counterparty | Where it comes from |
|---|---|---|
| borrows (sells the credit, buys the put) | buys the credit | an Earn pool's bid (bivium-curator), or a market maker's (bivium-protocol-mm) |
| sells a collar call | buys the call | a market maker's call bids on the loan's nested series |
| buys the call back | sells the call | the market maker that bought it, reselling from inventory |
| closes early (buys the credit back) | sells the credit | whoever holds it: a market maker resells; an Earn pool holds most of it and needs a sell path (requested of bivium-lending) |
The providers hedge off the loan's own book, mostly on a margined venue such as Deribit: an on-chain hedge locks its full collateral (the asset for a call, the strike in cash for a put). A collar call bought from a borrower can also be offset by a standard call sold on the options chain, when the spread pays for the BTC that locks (README).
The orientation is a choice, not a fact
Nothing in the series privileges one asset. Swap which one is locked and the same market reads as a different product.
The usual orientation is BTC collateral, stablecoin loan: a borrower who walks away forfeits BTC, so the lender is short a put on BTC. Turn it around — USDC collateral, WBTC loan — and the lender supplies BTC, is repaid in BTC if the borrower repays, and is paid in USDC above the strike if they do not. That lender is writing a covered call on bitcoin, and reached it through the lending contracts with no options product involved.
So "no-liquidation BTC lending" is one orientation of something with two, and a market maker can quote both sides of the inverted market from the same runner — it only needs the spot service's inverted pair. This is what "lending is a configuration" buys beyond tidiness.
LendingController
The series controller, consulted by the core on every mint, exercise and receipt whoever the
caller is — so the Exchange, Router and MaturitySettler work on lending markets without being
taught about lending. Market registration is permissionless and final: one market per set of terms,
rules fixed at registration, and the market id is the series id.
Lot size
Borrows and repayments move in whole multiples of lotUnits of collateral — for whole-lot BTC
vaults, say. With one exception that matters: whole lots, or the holder's entire remaining
balance. Longs transfer in any amount, so a holder left holding a fraction of a lot must still be
able to repay it in full rather than lose that collateral to a rule about tidiness.
The gate, and who may hold transiently
An optional gate answers canBorrow for receiving the repay right and canLend for receiving
credit. But protocol contracts have to pass through positions in the middle of a transaction, so the
controller also carries a set of intermediaries allowed to hold transiently.
That set is fixed in the constructor and deliberately has no setter, which is the sharper half of the design: whoever held such a setter could walk any address past every gate this controller serves. So it covers only the protocol contracts that must work on every gated market with no per-gate action — Exchange, Router, settler, flash exerciser. Anything deployed later, a collar router for instance, is admitted by the gate instead, which is the object that is supposed to be mutable and is already curated by the party who decides exactly this question.
What it can never do
Block an exit. Anyone may repay a whole lot on a holder's behalf — the collateral always goes to the
holder, so there is nothing to gain by doing it — and burnPair, collect and redeem do not
consult the controller at all. A gate decides who may enter.
Sweep is open on every market
Every LendingController market, that is: TBV markets have their own controller, which does not
implement canSweep, so the core refuses to sweep them (Architecture).
Anyone may repay every borrower's remaining debt at once, at their own expense: lenders get their
loan tokens as if every borrower had repaid, and borrowers get their collateral without paying. No
lot rule applies, because nothing is left behind, and no gate applies, because nobody receives a
token of the market.
It exists for a specific failure: a market that unrepaid dust holds below the core's
MIN_A_PER_SHARE takes no new borrows, and a
cheap 18-decimal collateral makes that easy to reach. Sweep is how such a market is made usable
again, by someone willing to pay for it.
LendingLens
Borrower debt and collateral, lender face and claimable, as views. Worth knowing it exists before reconstructing positions from logs — though note that TBV loans are not in it, because the TBV app holds their repay rights.
The Earn pool
Three contracts, split the way they are for a reason: InvestModule is the vault, HedgeDesk is
its hedging arm — a separate contract so the module stays under the size limit — and
CollateralDutchBook is a standalone liquidation lane usable on its own.
Lifecycle has the cycle in order and Curator has who operates it. What belongs here is the shape and the rules:
Taking the pool's side without the pool is a different thing and lands somewhere else entirely: writing a put or a call yourself is a plain series on the protocol, needing no lending deployment at all. The pool is what you buy when you want the rolling, the hedging and the limits done for you.
InvestModule
An ERC-4626-style vault over one loan token: depositors hold a transferable share of that token and never touch collateral. A pool is therefore per-currency, and a deployment runs one per currency it wants to offer — a USDC pool lends USDC against BTC, a WBTC pool lends WBTC against USDC.
The second of those is worth pausing on, because it is the
orientation choice wearing a different hat. A depositor
in a WBTC pool is lending bitcoin against dollars, so the pool is short a put on dollars priced in
bitcoin — which is a covered call on bitcoin. Same contract, same curator, same hedging
machinery; the depositor is simply on the other side of the same series. Nothing in InvestModule
distinguishes the two cases. It buys credit only as a maker, through its own ratified Exchange bids, and it
is its own ratifier — which is what turns its mandate from a promise into a precondition of
every fill — the module implements IFillCallback, so the Exchange calls it to fund the buy at the
moment of the fill rather than holding a standing approval.
IYieldSource is the second half of that idea and the half that has not happened: idle funds may
sit in a yield source and be drawn just in time by the same callback, but the source is optional
(address(0) means the funds must already be idle) and every module deployed so far has none.
Funding at fill time works; funding at fill time out of something that was earning does not yet.
On TBV markets: the redeemer
A TBV market's terms are encoded exactly as a lending market's, but its series lock vaultBTC, which
only the TBV app mints and the core pays out to no one else. So the module reads its rungs through
ISeriesSource — the seriesOf that LendingController and bivium-protocol-tbv's
TbvController both implement — and takes an optional redeemer (IRedeemingApp): the app a
product's credit is redeemed through. A pool built with the TBV app as its redeemer differs in three
ways, all fixed at construction:
- Its
lockedAssetis the app's vaultBTC, which every rung must lock, and itscollateralis the app's TBVBTC: what a default delivers, so what its puts are written on and its Dutch book sells. The constructor checks that the app names the controller and both tokens, and that they share decimals. - Harvest redeems the matured credit through the app, which pays TBVBTC and the loan token.
HedgeDesktakes a rung's strike from the series ratio, sinceTbvControllerhas noLendingController.marketto read it from.
Borrowers reach such a pool only through the app: borrowAgainst fills the module's own signed bid,
and a direct Exchange fill is refused by TbvController. The mandate, epochs, NAV and Dutch book are
the same contract. The deploy script (DeployTbvInvest.s.sol) and the end-to-end tests against the
real app live in bivium-protocol-tbv, because bivium-lending cannot depend on TBV's types.
NAV is amortized cost: credit accretes from cost to face by maturity, repayments realize at face, hedge premiums amortize to zero, and collateral awaiting sale is carried at its Dutch floor. Deposits and redemptions settle together once per epoch, with no instant path; an epoch cannot process while a matured rung is unharvested; redemptions fill pro-rata to liquid funds.
The limit of amortized cost is stated by the module's own docs rather than discovered later: NAV does not mark to market, so an informed holder could redeem ahead of a likely default. Epochs, the idle buffer and hedging bound it.
The mandate is what protects a depositor
In place of a price oracle, the module holds a mandate — the yield floor, the limits, custody and the settlement window — and loosening any of it waits out a timelock no shorter than an epoch after the curator schedules it, so a depositor can redeem first. Tightening is immediate. A guardian can pause and cancel a scheduled change. Before the first deposit, configuration is immediate.
Every fill is checked against it on-chain: natural side only, the yield floor (price plus the rung's
hedge premium per unit of face at most 1 − rMin·t), a bounded quote lifetime, the per-rung face
cap, the idle buffer, a cap on unhedged face across rungs, pause, and authorized quoter keys.
HedgeDesk
A rung's credit is short a put at the rung's strike; the desk buys it back, two ways:
- On-chain (
buyPut) — a fully collateralised bivium-protocol put at the rung's own strike, exercisable at its maturity, bought from a writer's ask. At harvest the delivered collateral goes into it and the module gets face. - Off-chain (
requestOffchain/completeOffchain/cancelOffchain) — a put bought on a venue and held in the pool's account under a custodian. The premium is escrowed and released to the pool's custody only against an allowed custodian key's attestation, or refunded. At harvest the covered collateral waits out a settlement window in which anyone may buy it at the strike, and the module gets face; after the window it falls through to the Dutch book.
The honest failure case is written down: if everything off-chain fails, the pool is as if unhedged, less the premium. That is the cost of reaching venue liquidity the chain does not have.
Ordering is a rule, not a preference: hedge first, lend second — cover up to the rung's cap, a premium within the mandate, off-chain cover within its share of NAV.
CollateralDutchBook
Escrowed collateral on a linearly decaying ask down to a floor, partial fills by anyone, cancel and re-post after the window. Oracle-free, standalone, and reachable by anything that needs to turn collateral into the loan token without asking what it is worth.
It is the fallback, not the protection. It sells down to a floor and, in a crash below that, not at all — which is the whole argument for buying the put instead of relying on it.
What is not there yet
TBV vaultBTC collateral hooks on LendingController. TBV markets live under their own controller
instead, and the Earn pool reaches them through a redeemer.
Registration is final, so the scripts refuse to guess
DeployLending.s.sol checks that every protocol address it is given is a contract wired to the same
core, and RegisterMarket.s.sol registers one market permissionlessly and permanently. Both parse
the environment strictly: a set but malformed value reverts and never falls back to a default.
The worked example in the repo is the one to remember — a mistyped GATE would otherwise register
an open market, forever.
Vendored from bivium-protocol-doc 57ed1bdc6cfe, synced 2026-10-27. Where this and a repository disagree about that repository, the repository wins.