You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(asset-leasing): strip section numbers from headings; rewrite cross-references with word-based link text
WHAT: removed leading section numbers (1., 2., 3.1, 3.6, 3.8.1, etc.) from
every heading in defi/asset-leasing/anchor/README.md. Updated the table of
contents to point to the new numberless anchor slugs. Rewrote every
cross-reference (previously written as [§3.6](...) or [Section 4 (...)](...))
to use word-based link text drawn from the heading itself, so the link reads
as part of the surrounding prose.
WHY: clickable links should read naturally inside a sentence rather than
interrupt the reader with section-number references. Headings with leading
numbers also drift out of sync the moment a section is reordered or renamed.
Copy file name to clipboardExpand all lines: defi/asset-leasing/anchor/README.md
+41-41Lines changed: 41 additions & 41 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -17,23 +17,23 @@ anyway (think exchange-traded funds, pension funds, or any passive
17
17
allocator), and short sellers and arbitrageurs get the tokens they
18
18
need to sell short. The program is written in
19
19
[Anchor](https://solana.com/docs/terminology); a parallel
20
-
[Quasar port](#6-quasar-port) implements the same onchain behaviour.
20
+
[Quasar port](#quasar-port) implements the same onchain behaviour.
21
21
22
22
---
23
23
24
24
## Table of contents
25
25
26
-
1.[What does this program do?](#1-what-does-this-program-do)
27
-
2.[Accounts and program-derived addresses](#2-accounts-and-program-derived-addresses)
28
-
3.[Lifecycle](#3-lifecycle)
29
-
4.[Safety and edge cases](#4-safety-and-edge-cases)
30
-
5.[Running the tests](#5-running-the-tests)
31
-
6.[Quasar port](#6-quasar-port)
32
-
7.[Extending the program](#7-extending-the-program)
26
+
1.[What does this program do?](#what-does-this-program-do)
27
+
2.[Accounts and program-derived addresses](#accounts-and-program-derived-addresses)
28
+
3.[Lifecycle](#lifecycle)
29
+
4.[Safety and edge cases](#safety-and-edge-cases)
30
+
5.[Running the tests](#running-the-tests)
31
+
6.[Quasar port](#quasar-port)
32
+
7.[Extending the program](#extending-the-program)
33
33
34
34
---
35
35
36
-
## 1. What does this program do?
36
+
## What does this program do?
37
37
38
38
A **holder** offers some quantity of **token A** - the leased token -
39
39
for a fixed term. A **short seller** posts collateral in a different
@@ -165,7 +165,7 @@ rallies against the collateral. A drop in the borrowed asset price is
165
165
purely beneficial to the short seller. The streaming lending fee is
166
166
the position's only ongoing cost in either direction.
167
167
168
-
[Section 3 (Lifecycle)](#3-lifecycle) walks each instruction handler
168
+
The [lifecycle](#lifecycle) section walks each instruction handler
169
169
with concrete numbers that match the LiteSVM tests; the xNVDA example
170
170
above is the same machinery applied to a real asset pair.
171
171
@@ -176,11 +176,11 @@ above is the same machinery applied to a real asset pair.
176
176
inline in `liquidate.rs`. Production code would depend on the
177
177
`pyth-solana-receiver-sdk` crate so layout changes are caught at
178
178
compile time.
179
-
- See [Section 4 (Safety and edge cases)](#4-safety-and-edge-cases) for the rest of the deliberate simplifications.
179
+
- See [safety and edge cases](#safety-and-edge-cases) for the rest of the deliberate simplifications.
180
180
181
181
---
182
182
183
-
## 2. Accounts and program-derived addresses
183
+
## Accounts and program-derived addresses
184
184
185
185
Every call to the program touches some subset of these accounts. The
186
186
three [program-derived addresses](https://solana.com/docs/terminology)
@@ -254,7 +254,7 @@ record the terminal state, but the account disappears at the end.
254
254
255
255
---
256
256
257
-
## 3. Lifecycle
257
+
## Lifecycle
258
258
259
259
### What the short seller really gets
260
260
@@ -275,9 +275,9 @@ the cost of fulfilling the obligation later is fixed in tokens whose
275
275
price is unknown. Bet correctly on the direction and that asymmetry
276
276
prints money. Bet wrong and the cost of buying the tokens back can
277
277
exceed the cash plus the collateral, at which point the keepers
278
-
arrive (see [§3.6](#36-branch-position-underwater---liquidate)).
278
+
arrive (see [branch: position underwater - `liquidate`](#branch-position-underwater---liquidate)).
279
279
280
-
### 3.1 The holder lists the tokens - `create_lease`
280
+
### The holder lists the tokens - `create_lease`
281
281
282
282
The holder calls `create_lease`, naming the leased mint, the
283
283
collateral mint, the amount of leased tokens to offer, the
@@ -318,7 +318,7 @@ transfers to the program the moment the lease is listed.
318
318
-`InvalidMaintenanceMargin` if `maintenance_margin_basis_points` is `0` or `> 50_000`
319
319
-`InvalidLiquidationBounty` if `liquidation_bounty_basis_points > 2_000`
320
320
321
-
### 3.2 The short seller takes the offer - `take_lease`
321
+
### The short seller takes the offer - `take_lease`
322
322
323
323
A short seller who has spotted the `Lease` account onchain (via an
324
324
indexer or a direct lookup) calls `take_lease` to take delivery. The
@@ -357,7 +357,7 @@ moves from `Listed` to `Active`.
357
357
`collateral_mint` do not match the values stored on the lease
358
358
-`MathOverflow` if `now + duration_seconds` overflows `i64`
359
359
360
-
### 3.3 The lease fee streams - `pay_lease_fee`
360
+
### The lease fee streams - `pay_lease_fee`
361
361
362
362
The lease fee accrues second by second out of the collateral vault.
363
363
Anyone can call `pay_lease_fee` to settle whatever has accrued since
@@ -388,13 +388,13 @@ being liquidated, or defaulting; no further lease fees are owed.
388
388
- If the vault did not have enough collateral to cover the full
389
389
`lease_fee_due`, the residual is silently left as a debt the next
390
390
`liquidate` or `close_expired` call cleans up. (See
391
-
[Section 4 (Safety and edge cases)](#4-safety-and-edge-cases) for
391
+
[safety and edge cases](#safety-and-edge-cases) for
392
392
the rationale on this trade-off.)
393
393
-**Errors:**
394
394
-`InvalidLeaseStatus` if the lease is not `Active`
395
395
-`MathOverflow` if `elapsed * lease_fee_per_second` overflows `u64`
396
396
397
-
### 3.4 The short seller defends the position - `top_up_collateral`
397
+
### The short seller defends the position - `top_up_collateral`
398
398
399
399
If the price moves against the short seller and the position drifts
400
400
toward the maintenance-margin floor, the short seller can add more
@@ -423,7 +423,7 @@ is `Active`.
423
423
-`InvalidLeaseStatus` if the lease is not `Active`
424
424
-`MathOverflow` if the addition overflows `u64`
425
425
426
-
### 3.5 The short seller closes - `return_lease`
426
+
### The short seller closes - `return_lease`
427
427
428
428
To close the position, the short seller buys back the leased tokens
429
429
on the open market and calls `return_lease`. The program runs the
@@ -476,7 +476,7 @@ time at `end_timestamp`.
476
476
-`Unauthorised` if `lease.short_seller != short_seller.key()`
477
477
-`MathOverflow` if the lease-fee or collateral subtraction overflows
478
478
479
-
### 3.6 Branch: position underwater - `liquidate`
479
+
### Branch: position underwater - `liquidate`
480
480
481
481
If the leased asset rallies far enough that the locked collateral is
482
482
no longer worth more than the debt times the maintenance margin,
@@ -545,7 +545,7 @@ math non-negative (see [`is_underwater`](programs/asset-leasing/src/instructions
545
545
-`InvalidLeaseStatus` if the lease is not `Active`
546
546
-`MathOverflow` on any of the integer-multiplication steps
547
547
548
-
### 3.7 Branch: cancel or default - `close_expired`
548
+
### Branch: cancel or default - `close_expired`
549
549
550
550
The holder has a single recovery handler that covers two unrelated
551
551
situations:
@@ -591,7 +591,7 @@ rent-exempt-lamport refunds going to the holder.
591
591
-`InvalidLeaseStatus` if `status` is not `Listed` or `Active`
592
592
-`LeaseNotExpired` if `status == Active` and `now < end_timestamp`
593
593
594
-
### 3.8 Branch scenarios
594
+
### Branch scenarios
595
595
596
596
The handlers above cover the happy path. The branch scenarios below
597
597
walk the same machinery through liquidation, a falling-price profit,
@@ -615,9 +615,9 @@ Shared starting parameters:
615
615
The holder starts with 1 000 000 000 leased units; the short seller
616
616
starts with 1 000 000 000 collateral units. Each scenario opens with
617
617
`create_lease` and (where relevant) `take_lease` running as described
618
-
in [§3.1](#31-the-holder-lists-the-tokens---create_lease) and [§3.2](#32-the-short-seller-takes-the-offer---take_lease). Lease fees use the formula in [§3.3](#33-the-lease-fee-streams---pay_lease_fee).
618
+
in [the holder lists the tokens - `create_lease`](#the-holder-lists-the-tokens---create_lease) and [the short seller takes the offer - `take_lease`](#the-short-seller-takes-the-offer---take_lease). Lease fees use the formula in [the lease fee streams - `pay_lease_fee`](#the-lease-fee-streams---pay_lease_fee).
619
619
620
-
#### 3.8.1 Liquidation - leased asset rallies
620
+
#### Liquidation - leased asset rallies
621
621
622
622
`create_lease` and `take_lease` run as standard, leaving
623
623
`collateral_vault = 200_000_000`, `leased_vault = 0`, and the short
@@ -630,7 +630,7 @@ pot of ~200 000 000 - maintenance ratio is `200/400 = 50%`, far below
630
630
the required 120%. The keeper does not need to call `pay_lease_fee`
631
631
first; `liquidate` settles accrued fees itself.
632
632
633
-
The keeper calls `liquidate` (mechanics in [§3.6](#36-branch-position-underwater---liquidate)). At `T + 300`:
633
+
The keeper calls `liquidate` (mechanics in [branch: position underwater - `liquidate`](#branch-position-underwater---liquidate)). At `T + 300`:
has 200 000 000, so `lease_fee_payable = 3_000` flows to the holder.
@@ -655,7 +655,7 @@ The asymmetry to remember: liquidation does *not* reclaim the leased
655
655
tokens. The collateral pays the holder for the lost asset; the short
656
656
seller has effectively bought the leased tokens at the forfeit price.
657
657
658
-
#### 3.8.2 Falling price - short seller profits
658
+
#### Falling price - short seller profits
659
659
660
660
`create_lease` and `take_lease` run as standard. Time jumps to
661
661
`T + 300`. The leased-in-collateral price has fallen sharply: take
@@ -669,7 +669,7 @@ a healthy position.
669
669
At `T + 600` (10 minutes in) the short seller buys 100 leased tokens
670
670
on the open market at the new price (about 50 collateral tokens
671
671
total - far less than the 200 they posted) and calls `return_lease`
672
-
(mechanics in [§3.5](#35-the-short-seller-closes---return_lease)). Accrued lease fees are `600 × 10 = 6_000`
672
+
(mechanics in [the short seller closes - `return_lease`](#the-short-seller-closes---return_lease)). Accrued lease fees are `600 × 10 = 6_000`
673
673
collateral units. The settlement:
674
674
675
675
- 100 000 000 leased units flow short seller → leased vault → holder.
@@ -690,18 +690,18 @@ Final balances:
690
690
payoff.
691
691
692
692
The short seller can defend a borderline position with
693
-
`top_up_collateral` ([§3.4](#34-the-short-seller-defends-the-position---top_up_collateral)) or close it early via `return_lease`
694
-
([§3.5](#35-the-short-seller-closes---return_lease)). Only adverse price moves trigger liquidation.
693
+
`top_up_collateral` ([the short seller defends the position - `top_up_collateral`](#the-short-seller-defends-the-position---top_up_collateral)) or close it early via `return_lease`
694
+
([the short seller closes - `return_lease`](#the-short-seller-closes---return_lease)). Only adverse price moves trigger liquidation.
695
695
696
-
#### 3.8.3 Default - `close_expired` on an `Active` lease
696
+
#### Default - `close_expired` on an `Active` lease
697
697
698
698
`create_lease` and `take_lease` run as standard. The short seller
699
699
takes the tokens, posts collateral, then disappears. `pay_lease_fee`
700
700
is never called. The clock advances past
701
701
`end_timestamp = T + 86_400`.
702
702
703
703
At `T + 100_000` the holder calls `close_expired` (mechanics in
704
-
[§3.7](#37-branch-cancel-or-default---close_expired)). Because `status == Active` and `now >= end_timestamp`, the
704
+
[branch: cancel or default - `close_expired`](#branch-cancel-or-default---close_expired)). Because `status == Active` and `now >= end_timestamp`, the
705
705
default branch runs:
706
706
707
707
-`leased_vault` is empty (the short seller kept the tokens) - no
@@ -719,11 +719,11 @@ Final balances:
719
719
-**Short seller:** 100 000 000 leased units, paid the full
720
720
collateral and kept the leased tokens.
721
721
722
-
#### 3.8.4 Cancel - `close_expired` on a `Listed` lease
722
+
#### Cancel - `close_expired` on a `Listed` lease
723
723
724
724
The cheap cancel path. `create_lease` runs; no short seller ever
725
725
calls `take_lease`. The holder calls `close_expired` immediately
726
-
(mechanics in [§3.7](#37-branch-cancel-or-default---close_expired)). Because `status == Listed`, no expiry check
726
+
(mechanics in [branch: cancel or default - `close_expired`](#branch-cancel-or-default---close_expired)). Because `status == Listed`, no expiry check
727
727
applies:
728
728
729
729
-`leased_vault` holds 100 000 000 leased units; all of it drains
@@ -736,9 +736,9 @@ nothing else moved.
736
736
737
737
---
738
738
739
-
## 4. Safety and edge cases
739
+
## Safety and edge cases
740
740
741
-
### 4.1 What the program refuses to do
741
+
### What the program refuses to do
742
742
743
743
All of the following come from [`errors.rs`](programs/asset-leasing/src/errors.rs)
744
744
and are enforced by either an Anchor constraint or a `require!` in the
@@ -761,7 +761,7 @@ handler:
761
761
-**`LeasedMintEqualsCollateralMint`** - `create_lease` called with the same mint for both sides.
762
762
-**`PriceFeedMismatch`** - `liquidate` called with a Pyth update whose `feed_id` does not match `lease.feed_id`.
763
763
764
-
### 4.2 Guarded design choices worth knowing
764
+
### Guarded design choices worth knowing
765
765
766
766
-**Leased tokens are locked up-front.**`create_lease` moves the tokens
767
767
into the `leased_vault` immediately, so a short seller calling
@@ -805,7 +805,7 @@ handler:
805
805
cut would dwarf the holder's recovery on default. The cap keeps
806
806
liquidation economics roughly in line with holder-first semantics.
807
807
808
-
### 4.3 Things the program does *not* guard against
808
+
### Things the program does *not* guard against
809
809
810
810
A production version of the program would want more:
811
811
@@ -847,7 +847,7 @@ A production version of the program would want more:
847
847
848
848
---
849
849
850
-
## 5. Running the tests
850
+
## Running the tests
851
851
852
852
All the tests are LiteSVM-based Rust integration tests under
853
853
[`programs/asset-leasing/tests/`](programs/asset-leasing/tests/). They
@@ -918,7 +918,7 @@ CI is already covered.
918
918
919
919
---
920
920
921
-
## 6. Quasar port
921
+
## Quasar port
922
922
923
923
A parallel implementation of the same program using
924
924
[Quasar](https://github.com/blueshift-gg/quasar) lives in
@@ -1019,7 +1019,7 @@ handler. Tests are in `src/tests.rs`.
1019
1019
1020
1020
---
1021
1021
1022
-
## 7. Extending the program
1022
+
## Extending the program
1023
1023
1024
1024
Directions a real-world version of the program would consider,
0 commit comments