How offer terms survive on-chain
Lesson 1 was the economic story. This lesson is the machinery: tokens and factories that carry terms and roles across multiple covenant transactions.
The problem
Creating a lending offer is not one transaction — it is a chain of covenant spends: mint tokens → lock collateral → accept → repay or liquidate. Each step must know the same terms (amounts, rate, expiry) and which party is acting.
Off-chain servers can lie or go offline. So the protocol embeds data in the chain itself — inside assets and transaction metadata.
Two ways to carry terms
| Approach | Where terms live | Source |
|---|---|---|
| Parameter tokens | Bit-packed into the amount field of 1-unit NFT UTXOs | Official docs |
| OP_RETURN metadata | Fixed-length blob in offer-creation tx (rate, expiry, principal asset, amounts) | simplicity-lending |
Both solve the same problem: immutable offer parameters across covenant spends. When reviewing code, check which pattern it implements — the indexer verification rules differ. Details: Parameter encoding reference.
Parameter tokens (official docs)
Liquid limits how much data fits in a UTXO amount (51 bits). The docs split parameters across two NFTs:
FIRST_PARAMETERS_NFT— interest rate, loan expiration block, decimal exponentsSECOND_PARAMETERS_NFT— base collateral amount, base principal amount
An indexer can extract these amounts, recompile the Pre-lock covenant, and compare its CMR (script hash) to output 0 — proving the tx is a genuine offer initialization.
Utility NFTs: terms + roles
Beyond parameters, the protocol mints role tokens — each a 1-unit Liquid asset glued to covenant logic:
| NFT | Purpose |
|---|---|
| Borrower NFT | Proves the borrower is spending; required to repay; burned on cancel/full repay |
| Lender NFT | Identifies the lender; unlocked when accepting; burned on liquidation |
| Protocol fee keeper | Authorizes withdrawals from the protocol-fee vault on repayment |
These are not collectibles — they are capabilities. Holding a borrower NFT means you can act as borrower in covenant spends. The indexer tracks NFT UTXOs to know who participates in each offer.
IssuanceFactory
In the reference implementation, each borrower sets up a personal IssuanceFactory covenant once. It mints the utility NFTs needed for each new offer.
The factory covenant has two witness paths (from issuance_factory.simf):
- IssueAssets — spends auth NFT + factory UTXO; issues new assets via Liquid issuance inputs; outputs role NFTs for one offer
- RemoveFactory — burns factory and auth NFTs when the borrower is done
Factory creation also writes OP_RETURN metadata: program id, issuing UTXO count, reissuance flags bitmask.
Covenant chain (tying it together)
Official docs order the first implementation as:
- Create utility tokens — parameter data + role NFTs (via factory in reference impl)
- Lock collateral — borrower builds lock / pending-offer covenant
- Set up lending — lender accepts, funds principal
- Settle lending — repay or liquidate
Lesson 1 reminder: collateral locks at step 2 (propose). Role NFTs are already minted at step 1 so the covenant knows who may spend which branch later.
Check your understanding
1. What do parameter tokens carry across covenant spends?
2. Who typically creates an IssuanceFactory covenant first?
3. What must a borrower NFT prove during repayment?
Try: “how does IssueAssets relate to create offer?” or “what’s the difference between parameter tokens and OP_RETURN metadata?”