Skip to content

XLS-65/66: Add LendingProtocolV1_1 two-step loan creation - #570

Open
Tapanito wants to merge 9 commits into
masterfrom
tapanito/loan-set-split
Open

Tapanito wants to merge 9 commits into
masterfrom
tapanito/loan-set-split

Conversation

@Tapanito

@Tapanito Tapanito commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • XLS-65: Adds AssetsReserved to the Vault ledger entry and vault_info RPC response under LendingProtocolV1_1. This field tracks assets reserved for pending Loans that have not yet been accepted.
  • XLS-66: Introduces a two-step loan creation flow under LendingProtocolV1_1 that eliminates the custom dual-signature requirement:
    • Adds Borrower and StartDate fields to LoanSet for creating a pending Loan proposal
    • Adds a separate LoanAccept transaction whose required transaction-specific field is LoanID
    • Adds the lsfLoanPending flag to the Loan ledger entry
    • Makes OwnerNode conditional until acceptance
    • Documents both signing flows (single-transaction and two-step)
    • Adds failure conditions and state changes for proposal, acceptance, and pending Loan deletion
    • Adds pending Loan checks to LoanManage and LoanPay

Motivation

The current LoanSet dual-signature workflow creates custody lock-in and limits adoption to custodians willing to build bespoke integrations. The two-step flow (propose + accept) uses standard XRPL transactions, enabling any wallet or custodian to participate.

Test plan

  • Review all new/modified field tables for correctness (Amendment column, types, defaults)
  • Verify failure conditions cover edge cases (expired proposals, pending Loan operations)
  • Confirm example JSON is valid and consistent with field definitions
  • Cross-check section numbering and internal cross-references

Comment thread XLS-0066-lending-protocol/README.md Outdated
Comment thread XLS-0066-lending-protocol/README.md
Introduces a dedicated `LoanAccept` transaction (type 84) for the
two-step loan creation flow instead of overloading `LoanSet` with
`tfLoanSetAccept`. Clarifies that expired pending loans require an
explicit `LoanDelete` to reclaim `Vault.AssetsReserved`.
Comment thread XLS-0066-lending-protocol/README.md Outdated
Comment thread XLS-0066-lending-protocol/README.md Outdated
Keep expired acceptances from mutating the pending Loan, assign LoanAccept type 83, and apply V1.1 cash-basis deltas on proposal and delete.

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broken anchor in cross-reference—link will 404. See inline.

Comment thread XLS-0066-lending-protocol/README.md Outdated

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the two-step loan flow (LoanAccept) and AssetsReserved additions are documented thoroughly, and the extensive section renumbering (3.9→3.12) plus internal anchor links were re-verified and are all correctly updated. TransactionType values (LoanAccept=83, LoanPay bumped to 84) avoid collisions, and the reserve/Vault bookkeeping for propose→accept→delete is symmetric. The one notable gap is that LoanAccept's state changes never recompute Loan.StartDate/NextPaymentDueDate after acceptance, even though the two-step flow's StartDate is described as an acceptance deadline rather than the loan's actual start.

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation-only change adding XLS-65 AssetsReserved and the XLS-66 two-step LoanSet/LoanAccept flow. The spec text is largely internally consistent (flag bitmasks don't collide, new anchors resolve correctly, reserve/vault bookkeeping nets out correctly across proposal/accept/delete). Two things worth double-checking before merge: the TransactionType reassignment for LoanPay, and whether interest should be recognized in Vault.AssetsTotal before a loan proposal is actually accepted.

@mvadari

mvadari commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

@ai-review --aggressive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The updated specs contain concrete field-table inaccuracies (e.g., incorrect internal types) and a mismatch between the PR description and the documented LoanSet additions that should be resolved before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates the XLS-65 and XLS-66 specifications to document the LendingProtocolV1_1 amendment, adding asset reservation accounting in Vaults and introducing a two-step loan creation flow (proposal + acceptance) using a new LoanAccept transaction.

Changes:

  • XLS-65: Adds AssetsReserved to the Vault ledger entry and vault_info RPC response to track assets reserved for pending loans.
  • XLS-66: Introduces pending-loan semantics (lsfLoanPending), adds LoanAccept, and updates LoanSet, LoanDelete, LoanManage, and LoanPay rules to support the two-step flow.
  • Expands/adjusts failure conditions and state changes to cover proposal expiration, acceptance, reserve transfer, and pending-loan deletion.
File summaries
File Description
XLS-0066-lending-protocol/README.md Documents the two-step loan creation flow and pending-loan lifecycle, adds LoanAccept, and updates related ledger/transaction behaviors.
XLS-0065-single-asset-vault/README.md Adds AssetsReserved to the Vault ledger entry and vault_info RPC response to support pending-loan asset reservation tracking.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread XLS-0065-single-asset-vault/README.md Outdated
Comment thread XLS-0066-lending-protocol/README.md Outdated
Comment thread XLS-0066-lending-protocol/README.md
Comment thread XLS-0066-lending-protocol/README.md Outdated

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found.

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a well-specified two-step loan creation flow for XLS-66 plus the AssetsReserved field for XLS-65. Cross-references, failure-condition numbering, and state-change bookkeeping (reserve/OwnerCount/Vault balances) are internally consistent between LoanSet proposal, LoanAccept, and pending-Loan deletion. One spec-table inconsistency stands out: AssetsReserved is marked as an unconditionally Required field on the Vault ledger entry even though it's gated behind the LendingProtocolV1_1 amendment (and is correctly marked optional in the vault_info RPC table), which mirrors the exact conditional treatment this same diff correctly applied to Loan.OwnerNode.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The spec introduces a transaction-type ID conflict (renumbering LoanPay) and has a missing data-verification rule for StartDate without Borrower, which must be resolved for protocol correctness and implementability.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

XLS-0066-lending-protocol/README.md:1547

  • LoanPay is currently specified as transaction type 84, but transaction type IDs are protocol constants and LoanPay was already assigned 83 in this spec. Keep LoanPay at 83 and assign the new ID (84) to LoanAccept instead.
| `TransactionType` |   Yes    |       `string`       |   `UINT16`    |     `84`      | The transaction type.                     |
  • Files reviewed: 2/2 changed files
  • Comments generated: 3
  • Review effort level: Lite

| `LoanID` | Yes | `string` | `HASH256` | `N/A` | The ID of the Loan object to be deleted. |
| Field Name | Required | JSON Type | Internal Type | Default Value | Description |
| ----------------- | :------: | :-------: | :-----------: | :-----------: | :--------------------------------------------- |
| `TransactionType` | Yes | `string` | `UINT16` | `83` | The transaction type. |
Comment on lines +1113 to +1114
19. `StartDate` is specified and either the `Counterparty` or the `CounterpartySignature` field is specified. (`temINVALID`)
20. `Borrower` is specified and `StartDate` is not specified. (`temINVALID`)
| `LateInterestRate` | Yes | Yes | `number` | `UINT32` | `N/A` | A premium is added to the interest rate for late payments in 1/10th basis points. Valid values are between 0 and 100000 inclusive. (0 - 100%) |
| `CloseInterestRate` | Yes | Yes | `number` | `UINT32` | `N/A` | An interest rate charged for repaying the Loan early in 1/10th basis points. Valid values are between 0 and 100000 inclusive. (0 - 100%) |
| `OverpaymentInterestRate` | Yes | Yes | `number` | `UINT32` | `N/A` | An interest rate charged on overpayments in 1/10th basis points. Valid values are between 0 and 100000 inclusive. (0 - 100%) |
| `StartDate` | Yes | Yes | `number` | `UINT32` | `CurrentLedgerTimestamp` | The timestamp of when the Loan started [Ripple Epoch](https://xrpl.org/docs/references/protocol/data-types/basic-data-types/#specifying-time). |
7. The LoanBroker _pseudo-account_ is deep frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
8. The Borrower is frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
9. The `LoanBroker.Owner` is deep frozen for the asset. (`tecFROZEN` for IOUs, `tecLOCKED` for MPTs)
10. Cannot add asset holding for the `Vault.Asset` (e.g., MPToken or TrustLine issues). (`tecNO_PERMISSION`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently return terNO_RIPPLE for IOU and tecNO_AUTH for MPT on develop so maybe we should update this and also for other transactors.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants