|
1 | 1 | # Asset Leasing |
2 | 2 |
|
3 | | -A fixed-term token lease on Solana, with a second-by-second lease fee |
4 | | -stream, a separate collateral deposit, and a Pyth-oracle-triggered |
5 | | -seizure path when the collateral is no longer worth enough. |
| 3 | +**On-chain securities lending.** Long holders rent out fungible token |
| 4 | +inventory to short sellers. Borrowers post collateral, pay a |
| 5 | +second-by-second lending fee, and return equivalent tokens before |
| 6 | +expiry. If the borrowed asset rallies past the maintenance margin, |
| 7 | +keepers liquidate the position; if it falls, the borrower profits and |
| 8 | +returns equivalent tokens cheaply. |
| 9 | + |
| 10 | +This is the same primitive that underpins traditional securities |
| 11 | +lending: long inventory holders (exchange-traded funds and pension |
| 12 | +funds in traditional finance; passive holders on-chain) earn yield on |
| 13 | +assets they would hold anyway, and short sellers and arbitrageurs get |
| 14 | +the borrow they need. The program is written in Anchor; a parallel |
| 15 | +[Quasar port](#7-quasar-port) implements the same on-chain behaviour. |
| 16 | + |
| 17 | +The code uses `lessor` / `lessee` identifiers throughout — those names |
| 18 | +predate the framing change and stay as-is so the source is grep-able. |
| 19 | +The README freely uses **lender** for the lessor and **borrower** (or |
| 20 | +**short seller**) for the lessee; they refer to the same on-chain |
| 21 | +roles. |
6 | 22 |
|
7 | 23 | Every instruction handler is walked through with the exact token |
8 | 24 | movements it causes. If you already know what collateral, a |
@@ -31,84 +47,72 @@ appear. |
31 | 47 |
|
32 | 48 | ## 1. What does this program do? |
33 | 49 |
|
34 | | -Two users, a **lessor** and a **lessee**, want to swap tokens |
35 | | -temporarily: |
36 | | - |
37 | | -- The lessor has some number of tokens of mint **A** (call it the |
38 | | - "leased mint") they would like to hand over for a fixed period of |
39 | | - time. |
40 | | -- The lessee has tokens of a different mint **B** (the "collateral |
41 | | - mint") they can lock up as a security deposit. |
| 50 | +A **lessor (lender)** offers some quantity of one fungible token — |
| 51 | +mint **A**, the "leased mint" — for a fixed term. A **lessee |
| 52 | +(borrower / short seller)** posts collateral in a different mint |
| 53 | +**B** — the "collateral mint" — to take delivery. The borrower will |
| 54 | +typically sell the A tokens immediately on a market like Jupiter, then |
| 55 | +re-acquire equivalent A tokens later to close out. Because mint A is |
| 56 | +fungible, the borrower only has to return the same *quantity*, not the |
| 57 | +exact units they received. |
42 | 58 |
|
43 | 59 | The program acts as a non-custodial escrow. It: |
44 | 60 |
|
45 | | -1. Takes the lessor's A tokens and locks them in a program-owned vault |
46 | | - until a lessee shows up. |
47 | | -2. When a lessee calls `take_lease`, the program locks the lessee's B |
48 | | - tokens as collateral and hands the A tokens to the lessee. |
49 | | -3. While the lease is live, a second-by-second **lease fee stream** |
50 | | - pays the lessor out of the collateral vault. |
51 | | -4. If the price of A (measured in B) moves against the lessee far enough |
52 | | - that the locked collateral is no longer enough to cover the cost of |
53 | | - re-acquiring the leased tokens, anyone can call `liquidate` — the |
54 | | - collateral is seized, most of it goes to the lessor, and a small |
55 | | - percentage (the **liquidation bounty**) goes to whoever called it. |
56 | | - Such a caller is known as a **keeper** — a bot or anyone else who |
57 | | - watches the chain for positions that have gone underwater and earns |
58 | | - the bounty by cleaning them up. |
59 | | -5. If the lessee returns the full A amount before the deadline, they get |
60 | | - back whatever collateral is left after lease fees. |
61 | | -6. If the lessee ghosts past the deadline without returning anything, |
62 | | - the lessor calls `close_expired` and sweeps the collateral as |
63 | | - compensation. |
| 61 | +1. Takes the lender's A tokens and locks them in a program-owned vault |
| 62 | + until a borrower shows up. |
| 63 | +2. When a borrower calls `take_lease`, the program locks the |
| 64 | + borrower's B tokens as collateral and hands the A tokens to the |
| 65 | + borrower. |
| 66 | +3. While the loan is live, a second-by-second **lending fee stream** |
| 67 | + pays the lender out of the collateral vault. |
| 68 | +4. If the price of A (measured in B) rises far enough that the locked |
| 69 | + collateral is no longer enough to cover the cost of re-acquiring |
| 70 | + the borrowed tokens, anyone can call `liquidate` — the collateral |
| 71 | + is seized, most of it goes to the lender, and a small percentage |
| 72 | + (the **liquidation bounty**) goes to whoever called it. Such a |
| 73 | + caller is known as a **keeper** — a bot or anyone else who watches |
| 74 | + the chain for positions that have gone underwater and earns the |
| 75 | + bounty by cleaning them up. |
| 76 | +5. If the borrower returns the full A amount before the deadline, they |
| 77 | + get back whatever collateral is left after lending fees. |
| 78 | +6. If the borrower ghosts past the deadline without returning |
| 79 | + anything, the lender calls `close_expired` and sweeps the |
| 80 | + collateral as compensation. |
64 | 81 |
|
65 | 82 | The trigger for step 4 is the **maintenance margin**: a ratio, |
66 | | -expressed in basis points (1 bp = 1/100 of a percent), of required |
67 | | -collateral value to debt value. `maintenance_margin_basis_points = 12_000` is |
68 | | -120%, meaning the collateral must stay worth at least 1.2× the leased |
69 | | -tokens. Drop below and the position becomes liquidatable. |
| 83 | +expressed in basis points (1 basis point = 1/100 of a percent), of |
| 84 | +required collateral value to debt value. |
| 85 | +`maintenance_margin_basis_points = 12_000` is 120%, meaning the |
| 86 | +collateral must stay worth at least 1.2× the borrowed tokens. Drop |
| 87 | +below and the position becomes liquidatable. |
70 | 88 |
|
71 | 89 | The program is a pair of vaults, a small piece of state that tracks |
72 | | -how much has been paid, and an oracle check. It is written in Anchor. |
73 | | - |
74 | | -### The tradfi picture, briefly |
75 | | - |
76 | | -Two analogies from finance for the uninitiated; the on-chain mechanics |
77 | | -above are the canonical description. |
78 | | - |
79 | | -- **Leasing gold bars from a bullion dealer.** The dealer hands over a |
80 | | - fixed amount of physical gold for a fixed period; the counterparty |
81 | | - pays a per-day leasing fee and posts cash collateral worth more than |
82 | | - the gold. If the gold price rises enough that the posted cash no |
83 | | - longer covers the value of the bars, the dealer can seize the cash |
84 | | - before the position goes further underwater. The leased tokens here |
85 | | - play the role of the gold; the collateral plays the role of the cash; |
86 | | - the oracle plays the role of a live gold price feed. |
| 90 | +how much has been paid, and an oracle check. |
87 | 91 |
|
88 | | -- **Securities lending — borrowing stock to short.** A broker lends |
89 | | - shares (say, NVIDIA) to a short seller for a fee. The short seller |
90 | | - posts cash collateral worth more than the shares. If NVIDIA rallies, |
91 | | - the collateral ratio falls; if it falls far enough, the broker issues |
92 | | - a margin call and, if unmet, liquidates the position by buying back |
93 | | - the shares from the collateral. This program's `liquidate` |
94 | | - instruction handler is the on-chain equivalent of that forced |
95 | | - buy-back. |
| 92 | +### Roles |
96 | 93 |
|
97 | | -Neither analogy is exact — real bullion leases and real securities |
98 | | -lending add features the program doesn't model (recall rights, rebate |
99 | | -rates, haircuts). |
| 94 | +- **Lessor / lender.** Long the asset, willing to part with it |
| 95 | + temporarily to earn the lending fee. The economic match for this |
| 96 | + role is a passive holder — someone who would hold the asset anyway |
| 97 | + and is happy to earn yield on idle inventory. |
| 98 | +- **Lessee / borrower / short seller.** Pays the lending fee for the |
| 99 | + right to sell the borrowed tokens now and buy them back later. The |
| 100 | + payoff shape is the same as a short: profit if the borrowed asset |
| 101 | + falls, loss (and possible liquidation) if it rises. |
| 102 | +- **Keeper / liquidator.** Standard role — watches for |
| 103 | + undercollateralised positions and takes the bounty for closing them. |
100 | 104 |
|
101 | | -### Worked example: leasing xNVDA against USDC |
| 105 | +### Worked example: shorting xNVDA via the lending market |
102 | 106 |
|
103 | 107 | Concrete numbers using assets that already trade on Solana — |
104 | 108 | [xNVDA](https://www.backed.fi/) (a Backed Finance / xStocks tokenised |
105 | 109 | NVIDIA share) and USDC. xNVDA has its own Pyth feed; the program |
106 | 110 | takes the feed id verbatim at `create_lease`. |
107 | 111 |
|
108 | 112 | Alice holds 100 xNVDA at ~$180 / share, ~$18 000 notional. She wants |
109 | | -yield without selling the underlying. |
| 113 | +yield on inventory she would hold anyway. |
110 | 114 |
|
111 | | -Bob wants short exposure to NVIDIA without using a perp. |
| 115 | +Bob wants short exposure to NVIDIA without using a perpetual future. |
112 | 116 |
|
113 | 117 | Alice lists the lease (assume USDC is 6-decimal, xNVDA is also |
114 | 118 | 6-decimal for round numbers): |
@@ -151,11 +155,11 @@ sells them on Jupiter for ~18 000 USDC at the spot price. |
151 | 155 | accrued lease fee. The remaining ~22 000 USDC (minus fees paid) |
152 | 156 | refunds to Bob. |
153 | 157 | - Bob's profit ≈ `$18 000 − $16 000 − fees − trading costs ≈ $2 000` |
154 | | - minus carry — the same payoff shape as a 30-day short on NVIDIA. |
| 158 | + minus carry. This is a 30-day short on NVIDIA, expressed on-chain. |
155 | 159 |
|
156 | | -The asymmetry: liquidation only ever fires when the *leased* asset |
157 | | -rallies against the collateral. A drop in the leased asset price is |
158 | | -purely beneficial to the lessee. The streaming lease fee is the |
| 160 | +The asymmetry: liquidation only ever fires when the *borrowed* asset |
| 161 | +rallies against the collateral. A drop in the borrowed asset price is |
| 162 | +purely beneficial to the borrower. The streaming lending fee is the |
159 | 163 | position's only ongoing cost in either direction. |
160 | 164 |
|
161 | 165 | §4 walks the on-chain token flows for each path with abstract numbers |
@@ -680,11 +684,14 @@ closed; all three rent-exempt lamport refunds go to the lessor. |
680 | 684 |
|
681 | 685 | ## 4. Full-lifecycle worked examples |
682 | 686 |
|
683 | | -All three use the same starting numbers so the arithmetic is easy to |
684 | | -follow. Both mints are 6-decimal tokens, so 1 token = 1 000 000 base |
685 | | -units. Throughout this section, "leased units" means base units of |
686 | | -the leased mint and "collateral units" means base units of the |
687 | | -collateral mint — they are descriptive labels, not real tickers. |
| 687 | +These are abstract walkthroughs of the same machinery the §1 xNVDA |
| 688 | +example uses, with round numbers chosen to make the arithmetic easy |
| 689 | +to follow and to match the LiteSVM tests one-to-one. All paths share |
| 690 | +the same starting parameters. Both mints are 6-decimal tokens, so |
| 691 | +1 token = 1 000 000 base units. Throughout this section, "leased |
| 692 | +units" means base units of the leased mint and "collateral units" |
| 693 | +means base units of the collateral mint — they are descriptive |
| 694 | +labels, not real tickers. |
688 | 695 | The diagrams use the same convention: `[<number> leased]` and |
689 | 696 | `[<number> collateral]`. |
690 | 697 |
|
@@ -802,14 +809,13 @@ Same setup. Steps 1 and 2 run identically. |
802 | 809 | tokens. The collateral pays the lessor for the lost asset. The lessee |
803 | 810 | has effectively bought the leased tokens at the forfeit price.) |
804 | 811 |
|
805 | | -### 4.3 Falling-price path — lessee benefits |
| 812 | +### 4.3 Falling-price path — borrower profits |
806 | 813 |
|
807 | 814 | Liquidation is a one-sided risk: it only ever fires when the leased |
808 | 815 | asset *appreciates* against the collateral. If the leased asset |
809 | | -depreciates, the collateral ratio rises and the lessee's position |
810 | | -gets safer. Mechanically the position behaves like a short on the |
811 | | -leased asset — gains accrue to the lessee, the only ongoing cost is |
812 | | -the streaming lease fee. |
| 816 | +depreciates, the collateral ratio rises and the borrower's position |
| 817 | +gets safer. The streaming lending fee is the position's only ongoing |
| 818 | +cost. |
813 | 819 |
|
814 | 820 | Same setup. Steps 1 and 2 run identically. |
815 | 821 |
|
@@ -844,18 +850,16 @@ Same setup. Steps 1 and 2 run identically. |
844 | 850 |
|
845 | 851 | - Lessor: 1 000 000 000 leased units (full return), 6 000 collateral units in lease |
846 | 852 | fees. |
847 | | -- Lessee: 100 000 000 leased units received → bought 100 leased tokens |
848 | | - back at the lower price → returned them. Their net cost is the |
849 | | - lease fee (6 000 collateral units) plus whatever |
850 | | - they paid on the open market for the replacement leased tokens; |
851 | | - their gain is the difference between what they originally received |
852 | | - the leased tokens at versus what they paid to re-acquire them. |
853 | | -
|
854 | | -This is the same payoff shape as a short on the leased asset: the |
855 | | -lessee profits from price drops and pays a small carry (the lease |
856 | | -fee) for the duration. Only adverse moves trigger liquidation, and |
857 | | -the lessee can defend a borderline position with `top_up_collateral` |
858 | | -or close it early via `return_lease`. |
| 853 | +- Lessee: received 100 000 000 leased units, sold them at the |
| 854 | + original price, bought 100 leased tokens back at the lower price, |
| 855 | + returned them. Net cost is the lending fee (6 000 collateral units) |
| 856 | + plus whatever they paid on the open market for the replacement |
| 857 | + tokens; gain is the difference between the original sale price and |
| 858 | + the buy-back price. The standard short payoff. |
| 859 | +
|
| 860 | +The borrower can defend a borderline position with |
| 861 | +`top_up_collateral` or close it early via `return_lease`. Only |
| 862 | +adverse price moves trigger liquidation. |
859 | 863 |
|
860 | 864 | ### 4.4 Default / expiry path — `close_expired` on an `Active` lease |
861 | 865 |
|
|
0 commit comments