mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-24 07:30:30 +00:00
Fix MPT transfer fee on small escrow
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
@@ -213,10 +214,25 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
auto finalAmt = amount;
|
||||
if ((!senderIssuer && !receiverIssuer) && lockedRate != kParityRate)
|
||||
{
|
||||
// compute transfer fee, if any
|
||||
auto const xferFee = amount.value() - divideRound(amount, lockedRate, amount.asset(), true);
|
||||
// compute balance to transfer
|
||||
finalAmt = amount.value() - xferFee;
|
||||
if (view.rules().enabled(featureMPTokensV2))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
lockedRate >= kParityRate,
|
||||
"xrpl::escrowUnlockApplyHelper<MPTIssue> : lockedRate is at least parity");
|
||||
// MPTs are integral, so round the delivered amount down and
|
||||
// charge any fractional transfer fee to the escrowed amount.
|
||||
auto const delivered =
|
||||
mulRatio(amount.mpt(), kParityRate.value, lockedRate.value, false);
|
||||
finalAmt = STAmount(amount.asset(), delivered.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute transfer fee, if any
|
||||
auto const xferFee =
|
||||
amount.value() - divideRound(amount, lockedRate, amount.asset(), true);
|
||||
// compute balance to transfer
|
||||
finalAmt = amount.value() - xferFee;
|
||||
}
|
||||
}
|
||||
return unlockEscrowMPT(
|
||||
view,
|
||||
|
||||
@@ -3679,6 +3679,72 @@ struct EscrowToken_test : public beast::unit_test::Suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMPTSplitEscrowTransferFee(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
bool const withMPTokensV2 = features[featureMPTokensV2];
|
||||
testcase(
|
||||
std::string("MPT Split Escrow Transfer Fee ") +
|
||||
(withMPTokensV2 ? "with MPTokensV2" : "without MPTokensV2"));
|
||||
|
||||
Env env{*this, features};
|
||||
auto const baseFee = env.current()->fees().base;
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const gw = Account("gw");
|
||||
env.fund(XRP(1'000), alice, bob, gw);
|
||||
env.close();
|
||||
|
||||
MPTTester const mpt({
|
||||
.env = env,
|
||||
.issuer = gw,
|
||||
.holders = {alice, bob},
|
||||
.transferFee = 1'000,
|
||||
.flags = tfMPTCanEscrow | tfMPTCanTransfer,
|
||||
});
|
||||
env(pay(gw, alice, mpt(10'000)));
|
||||
env.close();
|
||||
|
||||
static constexpr int escrowCount = 10;
|
||||
static constexpr int splitAmount = 10;
|
||||
static constexpr int totalLocked = escrowCount * splitAmount;
|
||||
std::array<std::uint32_t, escrowCount> seqs{};
|
||||
for (auto& seq : seqs)
|
||||
{
|
||||
seq = env.seq(alice);
|
||||
env(escrow::create(alice, bob, mpt(splitAmount)),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kFinishTime(env.now() + 1s),
|
||||
Fee(baseFee * 150));
|
||||
env.close();
|
||||
}
|
||||
|
||||
BEAST_EXPECT(env.balance(alice, mpt) == mpt(10'000 - totalLocked));
|
||||
BEAST_EXPECT(env.balance(bob, mpt) == mpt(0));
|
||||
BEAST_EXPECT(env.balance(gw, mpt) == mpt(-10'000));
|
||||
BEAST_EXPECT(mptEscrowed(env, alice, mpt) == totalLocked);
|
||||
BEAST_EXPECT(issuerMPTEscrowed(env, mpt) == totalLocked);
|
||||
|
||||
for (auto const seq : seqs)
|
||||
{
|
||||
env(escrow::finish(bob, alice, seq),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kFulfillment(escrow::kFb1),
|
||||
Fee(baseFee * 150));
|
||||
env.close();
|
||||
}
|
||||
|
||||
auto const feeBurned = withMPTokensV2 ? escrowCount : 0;
|
||||
BEAST_EXPECT(env.balance(alice, mpt) == mpt(10'000 - totalLocked));
|
||||
BEAST_EXPECT(env.balance(bob, mpt) == mpt(totalLocked - feeBurned));
|
||||
BEAST_EXPECT(env.balance(gw, mpt) == mpt(-10'000 + feeBurned));
|
||||
BEAST_EXPECT(mptEscrowed(env, alice, mpt) == 0);
|
||||
BEAST_EXPECT(issuerMPTEscrowed(env, mpt) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
testMPTRequireAuth(FeatureBitset features)
|
||||
{
|
||||
@@ -3997,6 +4063,8 @@ public:
|
||||
testMPTWithFeats(feats);
|
||||
testMPTWithFeats(feats - fixTokenEscrowV1);
|
||||
}
|
||||
testMPTSplitEscrowTransferFee(all - featureMPTokensV2);
|
||||
testMPTSplitEscrowTransferFee(all);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user