fix: Charge transfer fee on third-party vault withdrawals

A VaultWithdraw that names a Destination other than the submitter
delivered the asset with the issuer's transfer fee waived. Depositing
into a vault and withdrawing to someone else therefore moved IOUs and
MPTs without paying the fee.

Under fixCleanup3_5_0 the withdrawer's vault position pays the fee. A
fixed-asset request still delivers the requested amount and redeems
enough shares to cover the gross cost. A fixed-share request burns the
requested shares and delivers what is left after the fee. Withdrawals
to the submitter or to the issuer stay fee-free. The fee is settled by
redeeming the gross amount with the issuer and issuing the net amount
to the destination. ValidVault expects the destination delta to be the
vault outflow less the fee.
This commit is contained in:
Timur Ialymov
2026-09-22 21:47:36 +01:00
parent 8f4e9c25d8
commit e6a5157891
8 changed files with 594 additions and 51 deletions

View File

@@ -265,6 +265,13 @@ canWithdraw(
[[nodiscard]] TER
canWithdraw(ReadView const& view, STTx const& tx);
/**
* Pays out a withdrawal from a vault or loan broker pseudo-account.
*
* `sourceAmount` leaves `sourceAcct` and `destinationAmount` reaches `dstAcct`.
* The two differ only when the withdrawal carries a transfer fee; the
* difference is the fee and is settled through the issuer.
*/
[[nodiscard]] TER
doWithdraw(
ApplyViewContext ctx,
@@ -272,7 +279,8 @@ doWithdraw(
AccountID const& dstAcct,
AccountID const& sourceAcct,
XRPAmount priorBalance,
STAmount const& amount,
STAmount const& destinationAmount,
STAmount const& sourceAmount,
beast::Journal j);
/**

View File

@@ -316,6 +316,13 @@ transferRate(ReadView const& view, Asset const& asset);
[[nodiscard]] Rate
transferRate(ReadView const& view, STAmount const& amount);
/**
* Returns the amount delivered when the transfer fee is deducted from a fixed
* source amount.
*/
[[nodiscard]] STAmount
subtractTransferFee(STAmount const& sourceAmount, Rate const& rate);
//------------------------------------------------------------------------------
//
// Holding operations (Asset-based dispatchers)