From 1fa366576e07f72beeab8b4f47737bf0afbb1169 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Mon, 10 Nov 2025 13:05:51 -0500 Subject: [PATCH] doc: Expand explanation for LoanBrokerCoverClawback::determineBrokerID --- .../app/tx/detail/LoanBrokerCoverClawback.cpp | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/xrpld/app/tx/detail/LoanBrokerCoverClawback.cpp b/src/xrpld/app/tx/detail/LoanBrokerCoverClawback.cpp index 453431964e..f4a6f6ba20 100644 --- a/src/xrpld/app/tx/detail/LoanBrokerCoverClawback.cpp +++ b/src/xrpld/app/tx/detail/LoanBrokerCoverClawback.cpp @@ -57,26 +57,44 @@ LoanBrokerCoverClawback::preflight(PreflightContext const& ctx) Expected determineBrokerID(ReadView const& view, STTx const& tx) { + // If the broker ID was provided in the transaction, that's all we + // need. if (auto const brokerID = tx[~sfLoanBrokerID]) return *brokerID; + // If the broker ID was not provided, and the amount is either + // absent or holds a non-IOU - including MPT, something went wrong, + // because that should have been rejected in preflight(). auto const dstAmount = tx[~sfAmount]; if (!dstAmount || !dstAmount->holds()) return Unexpected{tecINTERNAL}; // LCOV_EXCL_LINE - // Since we don't have a LoanBrokerID, holder _should_ be the loan broker's - // pseudo-account, but we don't know yet whether it is, so use a generic - // placeholder name. - auto const holder = dstAmount->getIssuer(); - auto const sle = view.read(keylet::account(holder)); + // Every trust line is bidirectional. Both sides are simultaneously + // issuer and holder. For this transaction, the Account is acting as + // a holder, and clawing back funds from the LoanBroker + // Pseudo-account acting as holder. If the Amount is an IOU, and the + // `issuer` field specified in that Amount is a LoanBroker + // Pseudo-account, we can get the LoanBrokerID from there. + // + // Thus, Amount.issuer _should_ be the loan broker's + // pseudo-account, but we don't know yet whether it is. + auto const maybePseudo = dstAmount->getIssuer(); + auto const sle = view.read(keylet::account(maybePseudo)); + + // If the account was not found, the transaction can't go further. if (!sle) return Unexpected{tecNO_ENTRY}; + // If the account was found, and has a LoanBrokerID (and therefore + // is a pseudo-account), that's the + // answer we need. if (auto const brokerID = sle->at(~sfLoanBrokerID)) return *brokerID; - // Or tecWRONG_ASSET? + // If the account does not have a LoanBrokerID, the transaction + // can't go further, even if it's a different type of Pseudo-account. return Unexpected{tecOBJECT_NOT_FOUND}; + // Or tecWRONG_ASSET? } Expected