Skip to content

fix: Keep non-transferable MPT loan fees off the broker owner - #8152

Open
tyalymov wants to merge 3 commits into
developfrom
tialymov/FN-101-loanpay_mpt_cantransfer
Open

fix: Keep non-transferable MPT loan fees off the broker owner#8152
tyalymov wants to merge 3 commits into
developfrom
tialymov/FN-101-loanpay_mpt_cantransfer

Conversation

@tyalymov

@tyalymov tyalymov commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

High Level Overview of Change

LoanPay credited the broker owner even when the vault MPT had lsfMPTCanTransfer cleared. Payment already rejects that hop with tecNO_AUTH. Under fixCleanup3_4_0 the fee uses the existing cover fallback. Repayment to the vault is unchanged, matching the CoverWithdraw recovery path.

Context of Change

accountSendMulti does not enforce MPT transferability. LoanBrokerCoverDeposit calls canTransfer before sending. LoanBrokerCoverWithdraw and VaultWithdraw only skip it with an explicit, amendment-gated waiver after fixCleanup3_2_0. LoanPay had neither.

sendBrokerFeeToOwner already falls back to the broker pseudo-account when cover is low, the owner is deep-frozen, or StrongAuth fails. Transferability was missing from that list, so a Dynamic MPT whose issuer later cleared lsfMPTCanTransfer still paid the owner.

Repayment (borrower to vault, or the cover fallback) is a recovery path: blocking it would let an issuer halt servicing of every outstanding loan by clearing one flag. The MPT invariant already treats ttLOAN_PAY that way after fixCleanup3_2_0. This change only stops the owner fee.

IOU routing is unchanged. The new check runs only for MPT assets.

API Impact

  • Public API: New feature (new methods and/or new fields)
  • Public API: Breaking change (in general, breaking changes should only impact the next api_version)
  • libxrpl change (any change that may affect libxrpl or dependents of libxrpl)
  • Peer protocol change (must be backward compatible or bump the peer protocol version)

The consensus result of LoanPay changes under fixCleanup3_4_0 when the vault asset is a non-transferable MPT and the broker owner is not the issuer: the fee is credited to cover instead of the owner.

Test Plan

LoanPay cases for a vault MPT with lsfMPTCanTransfer cleared after origination:

  • Post-fixCleanup3_4_0: ordinary LoanPay succeeds, the vault is repaid, the fee goes to cover, a holder-to-holder Payment still fails tecNO_AUTH.
  • Pre-amendment: the same payment still credits the owner.

tyalymov and others added 3 commits September 1, 2026 13:22
LoanPay sent the management fee to the broker owner even after the issuer
cleared lsfMPTCanTransfer. Payment rejects that hop with tecNO_AUTH.
Under fixCleanup3_4_0 the fee goes to the cover pool instead. Vault
repayment still succeeds, as CoverWithdraw does after fixCleanup3_2_0.

Co-authored-by: Cursor <cursoragent@cursor.com>
Name the cover/freeze/auth gate and return isTesSuccess from canTransfer
instead of a nested TER check. Drop the comment on the untouched send.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

@xrplf-ai-reviewer xrplf-ai-reviewer Bot 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.

The change adds an MPT-transferability check to LoanPay's broker-fee routing, gated by fixCleanup3_4_0, so that a Dynamic MPT whose issuer clears lsfMPTCanTransfer falls back to the cover/pseudo-account path instead of crediting the broker owner directly. The boolean refactor (cannotSendFeeToOwner) is logically equivalent to the prior condition, the new canTransfer check correctly uses accountID_ (a non-issuer holder, mirroring the borrower-side Payment check) as the transfer-check source, and dst=brokerOwner naturally lets issuer-owner cases succeed. IOU/XRP routing is untouched since the check is gated on asset.holds(). New tests exercise both the pre- and post-amendment behavior, verifying vault repayment still succeeds while fee routing differs, and use a documented ledger-poking technique consistent with existing test patterns in this file. I did not find a correctness, security, or consistency issue in the diff that meets the bar for flagging.

@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

1 participant