From bfac68e308b8311118fc4829b8410773ef68d216 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Mon, 28 Jul 2025 19:50:26 -0400 Subject: [PATCH] Make VaultWithdraw with destination use the payment engine - Calls the same functions as LoanBrokerCoverWithdraw - See b34f59eafc, 10b73525be, 6b4236343a, and e6e6360c1a - Many unit test failures. I'm not sure how accurate they are --- src/xrpld/app/tx/detail/VaultWithdraw.cpp | 74 +++++++++++++++++++---- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/src/xrpld/app/tx/detail/VaultWithdraw.cpp b/src/xrpld/app/tx/detail/VaultWithdraw.cpp index fc2ee114e3..25d24a32fa 100644 --- a/src/xrpld/app/tx/detail/VaultWithdraw.cpp +++ b/src/xrpld/app/tx/detail/VaultWithdraw.cpp @@ -1,4 +1,6 @@ #include +// +#include #include #include @@ -229,7 +231,7 @@ VaultWithdraw::doApply() assetsAvailable -= assetsWithdrawn; view().update(vault); - auto const& vaultAccount = vault->at(sfAccount); + AccountID const& vaultAccount = vault->at(sfAccount); // Transfer shares from depositor to vault. if (auto const ter = accountSend( view(), @@ -280,16 +282,66 @@ VaultWithdraw::doApply() return ter; } - // Transfer assets from vault to depositor or destination account. - if (auto const ter = accountSend( - view(), - vaultAccount, - dstAcct, - assetsWithdrawn, - j_, - WaiveTransferFee::Yes); - !isTesSuccess(ter)) - return ter; + if (dstAcct != account_ && !assetsWithdrawn.native()) + { + bool const mptDirect = assetsWithdrawn.holds(); + STAmount const maxSourceAmount = + Payment::getMaxSourceAmount(vaultAccount, assetsWithdrawn); + SLE::pointer sleDst = view().peek(keylet::account(dstAcct)); + if (!sleDst) + return tecINTERNAL; + + Payment::RipplePaymentParams paymentParams{ + .ctx = ctx_, + .maxSourceAmount = maxSourceAmount, + .srcAccountID = vaultAccount, + .dstAccountID = dstAcct, + .sleDst = sleDst, + .dstAmount = assetsWithdrawn, + .paths = STPathSet{}, + .deliverMin = std::nullopt, + .j = j_}; + + // If sending the assets to a different account, then this is + // effectively a payment. Use the Payment transaction code to call + // the payment engine, though only a subset of the functionality is + // supported in this transaction. e.g. No paths, no partial + // payments. + TER ret; + if (mptDirect) + { + ret = Payment::makeMPTDirectPayment(paymentParams); + } + else + { + ret = Payment::makeRipplePayment(paymentParams); + } + // Always claim a fee + if (!isTesSuccess(ret) && !isTecClaim(ret)) + { + JLOG(j_.info()) + << "LoanBrokerCoverWithdraw: changing result from " + << transToken(ret) + << " to tecPATH_DRY for IOU payment with Destination"; + return tecPATH_DRY; + } + if (ret) + return ret; + } + else + { + // Transfer assets from vault to depositor or destination (only if XRP) + // account. + if (auto const ter = accountSend( + view(), + vaultAccount, + dstAcct, + assetsWithdrawn, + j_, + WaiveTransferFee::Yes); + !isTesSuccess(ter)) + return ter; + } // Sanity check if (accountHolds(