mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 01:06:48 +00:00
Fix Offer Crossing Rounds Transfer-Fee Burn Down To Zero
This commit is contained in:
@@ -652,7 +652,15 @@ limitStepIn(
|
||||
// under an amendment.
|
||||
ofrAmt = offer.limitIn(ofrAmt, inLmt, /* roundUp */ false);
|
||||
stpAmt.out = ofrAmt.out;
|
||||
ownerGives = mulRatio(ofrAmt.out, transferRateOut, QUALITY_ONE, /*roundUp*/ false);
|
||||
// Round up for MPT output so the offer owner pays the full
|
||||
// ceil(amount × rate) fee, matching direct Payment semantics. IOU uses
|
||||
// floating-point arithmetic so the floor/ceil distinction is sub-epsilon
|
||||
// there; preserve the historical false to avoid changing IOU behavior.
|
||||
ownerGives = mulRatio(
|
||||
ofrAmt.out,
|
||||
transferRateOut,
|
||||
QUALITY_ONE,
|
||||
/*roundUp*/ std::is_same_v<TOut, MPTAmount>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,7 +679,11 @@ limitStepOut(
|
||||
if (limit < stpAmt.out)
|
||||
{
|
||||
stpAmt.out = limit;
|
||||
ownerGives = mulRatio(stpAmt.out, transferRateOut, QUALITY_ONE, /*roundUp*/ false);
|
||||
ownerGives = mulRatio(
|
||||
stpAmt.out,
|
||||
transferRateOut,
|
||||
QUALITY_ONE,
|
||||
/*roundUp*/ std::is_same_v<TOut, MPTAmount>);
|
||||
ofrAmt = offer.limitOut(
|
||||
ofrAmt,
|
||||
stpAmt.out,
|
||||
@@ -770,7 +782,11 @@ BookStep<TIn, TOut, TDerived>::forEachOffer(
|
||||
TAmounts stpAmt{mulRatio(ofrAmt.in, ofrInRate, QUALITY_ONE, /*roundUp*/ true), ofrAmt.out};
|
||||
|
||||
// owner pays the transfer fee.
|
||||
auto ownerGives = mulRatio(ofrAmt.out, ofrOutRate, QUALITY_ONE, /*roundUp*/ false);
|
||||
auto ownerGives = mulRatio(
|
||||
ofrAmt.out,
|
||||
ofrOutRate,
|
||||
QUALITY_ONE,
|
||||
/*roundUp*/ std::is_same_v<TOut, MPTAmount>);
|
||||
|
||||
auto const funds = offer.isFunded()
|
||||
? ownerGives // Offer owner is issuer; they have unlimited funds
|
||||
|
||||
@@ -2725,6 +2725,50 @@ public:
|
||||
using namespace jtx;
|
||||
auto const gw1 = Account("gateway1");
|
||||
|
||||
{
|
||||
auto const issuer = Account("issuer");
|
||||
auto const sender = Account("sender");
|
||||
auto const receiver = Account("receiver");
|
||||
auto const seller = Account("seller");
|
||||
auto const buyer = Account("buyer");
|
||||
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(10'000), issuer, sender, receiver, seller, buyer);
|
||||
env.close();
|
||||
|
||||
MPTTester mpt{
|
||||
{.env = env,
|
||||
.issuer = issuer,
|
||||
.holders = {sender, receiver, seller, buyer},
|
||||
.transferFee = 100}};
|
||||
MPT const token = mpt;
|
||||
|
||||
mpt.pay(issuer, sender, 2'000);
|
||||
mpt.pay(issuer, seller, 2'000);
|
||||
|
||||
// A direct holder-to-holder payment of 999 MPT at a 0.1% fee
|
||||
// requires 1000 from the sender and burns one MPT.
|
||||
env(pay(sender, receiver, token(999)), Ter(tecPATH_PARTIAL));
|
||||
env.close();
|
||||
env(pay(sender, receiver, token(999)), Sendmax(token(1'000)));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(mpt.getBalance(sender) == 1'000);
|
||||
BEAST_EXPECT(mpt.getBalance(receiver) == 999);
|
||||
BEAST_EXPECT(mpt.getBalance(issuer) == 3'999);
|
||||
|
||||
// CLOB crossing should apply the same fee quantum. The offer
|
||||
// owner pays ceil(999 * 1.001) = 1000, not floor(...) = 999.
|
||||
env(offer(seller, XRP(999), token(999)));
|
||||
env.close();
|
||||
env(offer(buyer, token(999), XRP(999)));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(mpt.getBalance(seller) == 1'000);
|
||||
BEAST_EXPECT(mpt.getBalance(buyer) == 999);
|
||||
BEAST_EXPECT(mpt.getBalance(issuer) == 3'998);
|
||||
}
|
||||
|
||||
auto test = [&](auto&& issue1, auto&& issue2) {
|
||||
Env env{*this, features};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user