emj
shrx

Lesson 5 · ~12 min · Lesson 4

On-chain state & transaction layout

PR #13 and #15 hinge on where outputs sit and what the covenant stores. This lesson fills that gap.

Mutable state on-chain

Offer parameters (rate, amounts, expiry) are fixed at creation. Two fields change during the loan — stored in Taproot data leaves via LendingOfferStorage:

SlotFieldPending offerAfter accept
0is_activefalsetrue
1current_debtprincipal + total feedecreases on partial repay

new_pending sets both slots before the collateral output is created. Acceptance flips is_active; repayment reduces current_debt. The indexer infers status from spends, but the covenant enforces debt math on-chain.

Supporting covenants

LendingOffer is not alone — it delegates to smaller programs. See supporting covenants reference for detail. Summary:

  • ScriptAuth — glues lender NFT to offer covenant until accept
  • AssetAuth — holds principal for borrower after accept
  • AssetAuthVault — holds repaid funds for lender/protocol claim

PR #13’s spike implements attach_creation for pending offers: lender NFT gets a ScriptAuth output, then metadata, then collateral locked in the main covenant.

Output index map (offer creation)

The indexer’s try_from_tx assumes a fixed layout. From simplicity-lending:

IndexOutput
2Borrower NFT
3Lender NFT (ScriptAuth-locked)
4OP_RETURN — 50-byte creation metadata
5Pending offer (collateral in covenant)

Earlier outputs (0–1) come from factory issuance in the same transaction. If your code places metadata or collateral at the wrong index, the tx may confirm but the indexer will ignore it.

Review checklist (PR #13) Does attach_creation produce 6+ outputs with metadata at index 4 and collateral covenant last? Does metadata encode 50 bytes (program id, principal asset, amount, expiry, rate)? Does new_pending set is_active=false and current_debt=total repayable?

Factory creation layout (PR #15)

IndexOutput
0Auth NFT
1Factory program UTXO
2OP_RETURN — 13-byte factory metadata

Full diagram: tx-output-layout.html.

Check your understanding

1. What does is_active=false mean for an offer?

2. Where does the indexer read offer metadata?

3. What is ScriptAuth used for in offer creation?