Repository navigation
Principal-only Vault/LoanBroker accounting #582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Tapanito
wants to merge
43
commits into
master
Choose a base branch
from
tapanito/lending-cash-basis
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 40 commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
5480349
adds cash-based share valuation
Tapanito ec48162
adds Vault version
Tapanito 8edeab3
update the spec to not skip SLEVersion 1
Tapanito 4a1b926
Merge branch 'master' into tapanito/lending-cash-basis
Tapanito 50abc3b
docs: align cash-basis Vault/LoanBroker text with develop
Tapanito bf4ee3e
docs: restate XLS-65.1 and XLS-66.1 patches in XLS template format
Tapanito 87a5819
docs: address PR 582 review comments
Tapanito ece0e37
docs(XLS-65.1): treat absent LEVersion as 0
Tapanito 118f612
docs: align cash-basis patches with develop accounting
Tapanito f485760
Merge remote-tracking branch 'origin/master' into tapanito/lending-ca…
Tapanito 0632fff
docs: number the Amendments section as an Introduction subsection
Tapanito 1d0f16d
docs: consolidate the LendingProtocolV1_1 patches into one document p…
Tapanito e5db49c
Merge remote-tracking branch 'origin/master' into tapanito/lending-ca…
Tapanito 215f13a
docs: restore cash-basis LoanBroker and LoanManage details
Tapanito df735b0
docs: match Vault Constant column and LoanSet phase checks
Tapanito 07ae495
docs: correct valueChange scope and cross-ref VaultKind to XLS-65.1
Tapanito 7819e26
Merge origin/master into tapanito/lending-cash-basis
Tapanito 64b6528
Merge origin/master into tapanito/lending-cash-basis
Tapanito 19a240a
docs(XLS-66): leave closed-ended lending rules to XLS draft
Tapanito 40201e9
docs: format cash-basis patches and inline amendment behaviour
Tapanito 0c8d45c
docs: scope LEVersion immutability and label the Vault excerpt
Tapanito bb136b8
docs: make DefaultAmount principal-only for cash-basis Vaults in form…
Tapanito edce470
docs: note that formula 34 is principal-only when LEVersion is 1
Tapanito 4c2a50a
docs: point closed-ended LendingProtocolV1_1 checks at PR 587
Tapanito 85be555
docs: add CoverAvailable to formula 35 and vault_info LEVersion
Tapanito 58a3ea8
Merge remote-tracking branch 'origin/master' into tapanito/lending-ca…
Tapanito f2219ad
style: apply prettier to vault and lending specs
Tapanito fe59dfc
docs: drop patch-title prefixes and name parent amendments
Tapanito c0847b9
Merge remote-tracking branch 'origin/master' into tapanito/lending-ca…
Tapanito 8e22494
docs: state origination InterestDue recognition and patch-over-parent…
Tapanito 80dbd85
Merge branch 'master' into tapanito/lending-cash-basis
Tapanito 8a68652
docs(XLS-65): gate the VaultSet cap invariant on fixCleanup3_4_0
Tapanito 9542a81
Merge origin/master and number cash-basis as XLS-65.1.3
Tapanito 34f8b77
docs: fix DebtTotal valueChange, AssetsMaximum cap, and 66.1 requires
Tapanito 7840c9b
docs: match VaultCreate AssetsMaximum to the deposit cap
Tapanito 4d3ae67
docs(XLS-65): split LoanSet cap invariant for cash-basis Vaults
Tapanito 90d9c00
docs(XLS-66): bump updated date and label legacy accounting examples
Tapanito c7f12a4
docs(XLS-66): label first-loss default example as legacy
Tapanito 375a7b0
docs(XLS-66): gate remaining valueChange prose to legacy Vaults
Tapanito 3c259da
docs: call legacy Vault accounting instant interest recognition
Tapanito 08873e0
Move cash-basis accounting into 65.1.3 and 66.1.1 patches
Tapanito a3f9aa8
Merge remote-tracking branch 'origin/master' into HEAD
Tapanito 5f81ed4
docs(XLS-66.1.1): keep parent LoanSet check numbers, add test plan, p…
Tapanito File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
85 changes: 85 additions & 0 deletions
85
XLS-0065-single-asset-vault/65.1/65.1.3-vault-cash-basis.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| <pre> | ||
| xls: 65.1.3 | ||
| title: Single Asset Vault Cash-Basis Accounting | ||
| description: Introduces Cash-Basis accounting for the Single Asset Vault | ||
| author: Vytautas Vito Tumas <vtumas@ripple.com> | ||
| proposal-from: https://github.com/XRPLF/XRPL-Standards/discussions/192 | ||
| status: Draft | ||
| category: Amendment | ||
| created: 2026-09-04 | ||
| updated: 2026-09-14 | ||
| </pre> | ||
|
|
||
| # 65.1.3 Single Asset Vault Cash-Basis Accounting | ||
|
|
||
| ## 1. Abstract | ||
|
|
||
| Under the `LendingProtocolV1_1` amendment, a Single Asset Vault accounts for the interest earned by its Loans on a cash basis. `AssetsTotal` counts interest only once a Borrower has paid it, rather than counting the interest a Loan is expected to earn from the moment the Loan is issued. The share exchange rate of the Vault therefore tracks the assets the Vault holds instead of the income it is owed, and a Borrower who stops paying costs the Vault only the principal it lent out. A Vault created before the amendment keeps instant interest recognition, in which `LoanSet` immediately adds all expected net `InterestDue` to `AssetsTotal` at origination (XLS-66 §3.8.6), because changing the accounting model of an existing Vault would change the value of the shares it has already issued. Which model a Vault uses is recorded in its `LEVersion` field and fixed when the Vault is created. | ||
|
|
||
| ## 2. Motivation | ||
|
|
||
| Instant interest recognition credits a Vault with interest that a Borrower has not paid yet, so the share exchange rate reflects income the Vault has not received. A depositor can redeem shares at a rate inflated by interest that later defaults, and the loss falls on the depositors who remain. Cash-basis accounting removes that mismatch by recognising interest only when it is paid. | ||
|
|
||
| Existing Vaults cannot switch accounting models without changing the value of shares already issued, so the model has to be recorded per Vault rather than derived from the amendment state at the time of the transaction. | ||
|
|
||
| ## 3. Specification | ||
|
|
||
| ### 3.1 Ledger Entry: `Vault` | ||
|
|
||
| #### 3.1.1 Fields | ||
|
|
||
| | Field Name | Constant | Required | Internal Type | Default Value | Description | | ||
| | ----------- | :------: | :------: | :-----------: | :-----------: | ------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `LEVersion` | Yes | No | `UINT8` | absent (`0`) | The accounting model the Vault applies to `AssetsTotal`. Absent is treated as `0` (instant interest recognition). Immutable once set. | | ||
|
|
||
| #### 3.1.2 `LEVersion` | ||
|
|
||
| `LEVersion` selects the accounting model of the Vault: | ||
|
|
||
| - `LEVersion` absent (treated as `0`, instant interest recognition): `AssetsTotal` includes the full expected net `InterestDue` booked at origination. This is the pre-amendment behaviour and continues to apply to every Vault created before the amendment was enabled. | ||
| - `LEVersion = 1` (cash basis): `AssetsTotal` excludes uncollected interest and increases only as interest is collected in cash. | ||
|
|
||
| The field is written once by `VaultCreate` and is immutable after creation. A Vault created while the amendment is enabled is always cash-basis, and a Vault created before it always uses instant interest recognition; neither can be converted to the other. | ||
|
|
||
| #### 3.1.3 Invariants | ||
|
|
||
| - On an update to an existing Vault: `Vault.LEVersion == Vault'.LEVersion`. Immutability of `LEVersion` is specified in [65.1.1 Unmodifiable Vault Fields](./65.1.1-unmodifiable-vault-fields.md). | ||
|
|
||
| #### 3.1.4 Partial Ledger Entry Example | ||
|
|
||
| The following excerpt shows the accounting fields introduced or affected by this patch; it is not a complete serialized `Vault` ledger entry: | ||
|
|
||
| ```json | ||
| { | ||
| "LedgerEntryType": "Vault", | ||
| "LEVersion": 1, | ||
| "Asset": { | ||
| "currency": "USD", | ||
| "issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" | ||
| }, | ||
| "AssetsTotal": "1000", | ||
| "AssetsAvailable": "1000" | ||
| } | ||
| ``` | ||
|
|
||
| ### 3.2 Transaction: `VaultCreate` | ||
|
|
||
| #### 3.2.1 Failure Conditions | ||
|
|
||
| No failure conditions related to cash-basis accounting are added or removed. `LEVersion` is not a transaction field and cannot be supplied by the submitter. | ||
|
|
||
| #### 3.2.2 State Changes | ||
|
|
||
| 1. Create a new `Vault` ledger object, setting `Vault.LEVersion = 1`. | ||
|
|
||
| ## 4. Rationale | ||
|
|
||
| The alternative to a per-entry version field is to derive the accounting model from the amendment state at the time each Loan transaction executes. That was rejected because it would silently change the share exchange rate of every existing Vault on the ledger at the moment the amendment activates. | ||
|
|
||
| `LEVersion` is a version number rather than a boolean flag so that a later accounting change can be expressed as a further version without another field. | ||
|
|
||
| ## 5. Security Considerations | ||
|
|
||
| Cash-basis accounting reduces, but does not remove, the exposure of a depositor to an unpaid Loan: the Vault still carries the principal at face value until the Loan defaults or is impaired. `LossUnrealized` remains the mechanism for reporting an expected shortfall. | ||
|
|
||
| Because `LEVersion` is immutable, an implementation must read it from the `Vault` ledger entry rather than from the amendment state when computing the interest accounting of a Loan. Reading the amendment state instead would apply cash-basis rules to Vaults that use instant interest recognition and misprice their shares. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.