The loan lifecycle
A MLKY loan moves through five clearly-defined states. The protocol enforces these transitions on-chain, so the same flow applies whether you use the MLKY app, a third-party UI, or interact with the program directly.
States and transitions
There is also a sixth state on the unhappy path: Defaulted, which the loan enters after maturity plus the grace period.
It is not terminal. A defaulted loan can still be repaid, and repaying
it moves it to Repaid and then Closed exactly like any other loan — the
card comes back. That right lasts until the card actually sells. See
default and liquidation for the
mechanics of that branch, including what happens to the money if the card
does sell.
There is also a transition that is not a transition. An active loan can be
extended, up to three times, which settles the interest you owe, reduces
your principal by at least 10% and restarts the term. The loan stays Active
throughout — it is the same loan repriced rather than a close and a reopen —
so it does not appear as a new state above. See
extending a loan.
Walking through each step
Step 1 — Request a signed quote
Before opening anything on-chain, you ask MLKY's oracle for a price. The oracle resolves your card's grading certificate to a canonical asset, fetches the current fair market value, and returns a signed quote that includes:
- The fair market value (FMV) in USDC.
- The maximum loan-to-value (LTV) permitted on this card, in basis points (a hundredth of a percent; 10,000 = 100%).
- The selected term length and interest rate.
- A unique quote id and an expiry timestamp.
Quotes are short-lived — they expire in 5 minutes by default. If you don't open a loan in that window, you simply request a new one.
Step 2 — Verify the Merkle proof
MLKY maintains an allowlist of every card eligible to be used as collateral, hashed into a Merkle tree (a hash tree of eligible cards) whose root the protocol stores on-chain. Before you create the loan, you submit a small proof showing your card is in the current tree. This produces a proof receipt account keyed by your card's certificate hash. The next step will consume that receipt.
This is a one-time-per-loan check. The proof itself is a few hundred bytes and the transaction is cheap.
Step 3 — Create the loan
You submit:
- The signed oracle quote (with the proper Ed25519 verify instruction).
- The proof receipt from the previous step.
- The pool you want to borrow from and the term option you want.
The program checks all the on-chain rules in one shot:
- The oracle's signature is valid and the oracle is on the allowlist.
- The Merkle root version on the quote matches a recent root the chain knows.
- The principal you're requesting is within the pool's
[min, max]range and withinFMV × LTVfor the card. - All the per-card and per-asset-type concentration limits are respected.
If everything passes, the loan is recorded in the Created state and a
short pending draw window opens — about 5 minutes — during which you
must complete the next step.
Step 4 — Draw the funds
Drawing is the moment money and collateral actually move:
- Your card-backed NFT transfers into the protocol's collateral vault (frozen, or for programmable NFTs, locked via a delegate slot).
- The pool sends you principal minus the origination fee in USDC.
- Concentration counters update: the pool's outstanding principal goes up, and the running exposure for this asset type increases by the principal.
- The loan transitions to
Active. The maturity clock starts at this moment, not when you created the loan.
Step 5 — Repay before maturity (the happy path)
To repay, you transfer principal plus the full fixed interest in a single transaction. There is no partial-repayment flow that closes the loan; anything less than the full payoff is rejected.
When the repayment lands:
- The pool's outstanding principal decreases by the principal you repaid.
- The loan moves to
Repaid. - A second instruction (often bundled in the same transaction by the app) closes the loan account, unlocks the NFT, and refunds you most of the rent that was paid for the loan's accounts.
You can repay at any point after drawing, including the same block. The interest is fixed, so there is no benefit to repaying earlier than your plan calls for, but there is no penalty either.
Closing does not immediately free the card for a new loan. One record — the
one keyed to your card's grading certificate — is kept for 48 hours and
carries the rent with it, so that a repayment cannot be turned straight back
into another loan. After the 48 hours you close that record yourself with
card_cooldown_release, which is when the last of the rent comes back and
when the card becomes borrowable again. See
extending a loan for why the wait exists.
Step 5 (alternate) — Extend instead of repaying
If you cannot repay, and you would rather not lose the card, you can renew.
loan_extend is one transaction and one transfer, carrying your outstanding
interest in full, a paydown of at least 10% of your principal, and a fresh
origination fee on the new term. When it lands:
- Your principal is lower, your maturity restarts from that moment, and your
loan is still
Active. The card never moves. - Your card is re-appraised against a fresh oracle quote, and the extension is refused if it has fallen far enough that even the reduced principal breaches the loan-to-value ceiling.
- Your extension count goes up. Three is the maximum; the fourth attempt is refused by name.
Only the loan's borrower can send it, and it is available for the whole of
Active — including after maturity and inside the grace period, which is
where most people who need it are standing. Once the loan is Defaulted it is
no longer available and redemption takes its place.
Extending a loan covers the arithmetic, with a worked example on a $500 loan.
Step 5 (alternate) — Default after maturity
If the maturity timestamp passes plus the grace period — which is your loan's
term or 7 days, whichever is shorter — the loan becomes eligible for
default. At that point anyone can submit
loan_mark_default_and_start_auction: it is permissionless, because the only
thing the caller asserts is that the clock has passed your deadline, and the
program checks that for itself. Expect it to be your lender or a keeper bot
watching for it. Submitting it atomically:
- Marks the loan as
Defaulted. - Initializes a new
Auctionaccount. The price starts at the card's appraised value from your loan's oracle snapshot and falls to your principal over 24 hours. - Starts the bidding window, which is a descending-price (Dutch) sale.
You get notice before this happens, and you can still repay afterwards.
Step 6 (alternate) — Redeem, or take the remainder
From Defaulted, two things can happen and only one of them is out of your
hands:
- You buy it back.
loan_redeem_from_auctiontakes aDefaultedloan and only you can sign it. Any standing bidder is refunded as a credit, the sale closes, and the card returns to you on the ordinaryRepaid → Closedpath. This is available until the card sells, and it has to be the whole payoff — a part payment is refused, because it would leave you in default with no sale left to end it. - The card sells. A 5% commission comes off the sale price, your lender
takes principal then interest, and the remainder is written as a
BorrowerCredityou claim with a single transaction. Claim it within twelve months: after that the protocol may sweep it, and it becomes a race you can lose.
The full mechanics are covered in default and liquidation and auctions overview.
What you do not do
A handful of things that exist in other lending protocols are intentionally absent here:
- No health-factor monitoring. Default is purely time-based: maturity passes, grace passes, you default. Price movements during the loan don't trigger early liquidation.
- No lender-initiated refinancing. Nobody but you can renew, reprice or call your loan. Some protocols let a lender who wants out auction your position to a stranger, which can force you into liquidation on a timetable you did not choose; MLKY has no such mechanism and will not build one. A lender leaves by withdrawing from the pool, not by moving your loan.
- No rate adjustments inside a term. The rate you accept when you open a
ticket is the rate you owe when it matures. Nothing can move it: a pool's
term options are not updatable at all, since
PoolUpdatableParamshas no field for them andterm_optionsis written only bypool_init. An extension does not move it either — it starts a new ticket, and you pick its term option the same way you picked the first.
Read next
- Terms and fees — the actual numbers involved.
- Default and liquidation — what the unhappy path looks like.
- Auctions overview — how a defaulted card is sold.