mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 19:15:54 +00:00
Add testDustManipulation test, which is expected to fail
This commit is contained in:
@@ -5637,6 +5637,162 @@ protected:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
testDustManipulation()
|
||||||
|
{
|
||||||
|
using namespace jtx;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
Env env(*this, all);
|
||||||
|
|
||||||
|
// Setup: Create accounts
|
||||||
|
Account issuer{"issuer"};
|
||||||
|
Account lender{"lender"};
|
||||||
|
Account borrower{"borrower"};
|
||||||
|
Account victim{"victim"};
|
||||||
|
|
||||||
|
env.fund(XRP(1'000'000'00), issuer, lender, borrower, victim);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// Step 1: Create vault with IOU asset
|
||||||
|
auto asset = issuer["USD"];
|
||||||
|
env(trust(lender, asset(100000)));
|
||||||
|
env(trust(borrower, asset(100000)));
|
||||||
|
env(trust(victim, asset(100000)));
|
||||||
|
env(pay(issuer, lender, asset(50000)));
|
||||||
|
env(pay(issuer, borrower, asset(50000)));
|
||||||
|
env(pay(issuer, victim, asset(50000)));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
BrokerParameters brokerParams{
|
||||||
|
.vaultDeposit = 10000,
|
||||||
|
.debtMax = Number{0},
|
||||||
|
.coverRateMin = TenthBips32{1000},
|
||||||
|
.coverRateLiquidation = TenthBips32{2500}};
|
||||||
|
|
||||||
|
auto broker = createVaultAndBroker(env, asset, lender, brokerParams);
|
||||||
|
|
||||||
|
auto const loanKeyletOpt = [&]() -> std::optional<Keylet> {
|
||||||
|
auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID));
|
||||||
|
if (!BEAST_EXPECT(brokerSle))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
// Broker has no loans
|
||||||
|
BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0);
|
||||||
|
|
||||||
|
// The loan keylet is based on the LoanSequence of the
|
||||||
|
// _LOAN_BROKER_ object.
|
||||||
|
auto const loanSequence = brokerSle->at(sfLoanSequence);
|
||||||
|
return keylet::loan(broker.brokerID, loanSequence);
|
||||||
|
}();
|
||||||
|
if (!loanKeyletOpt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto const vaultKeyletOpt = [&]() -> std::optional<Keylet> {
|
||||||
|
auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID));
|
||||||
|
if (!BEAST_EXPECT(brokerSle))
|
||||||
|
return std::nullopt;
|
||||||
|
return keylet::vault(brokerSle->at(sfVaultID));
|
||||||
|
}();
|
||||||
|
if (!BEAST_EXPECT(vaultKeyletOpt))
|
||||||
|
return;
|
||||||
|
auto const& vaultKeylet = *vaultKeyletOpt;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const vaultSle = env.le(vaultKeylet);
|
||||||
|
Number assetsTotal = vaultSle->at(sfAssetsTotal);
|
||||||
|
Number assetsAvail = vaultSle->at(sfAssetsAvailable);
|
||||||
|
|
||||||
|
log << "Before loan creation:" << std::endl;
|
||||||
|
log << " AssetsTotal: " << assetsTotal << std::endl;
|
||||||
|
log << " AssetsAvailable: " << assetsAvail << std::endl;
|
||||||
|
log << " Difference: " << (assetsTotal - assetsAvail) << std::endl;
|
||||||
|
|
||||||
|
// before the loan the assets total and available should be equal
|
||||||
|
BEAST_EXPECT(assetsAvail == assetsTotal);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
assetsAvail ==
|
||||||
|
broker.asset(brokerParams.vaultDeposit).number());
|
||||||
|
}
|
||||||
|
|
||||||
|
Keylet const& loanKeylet = *loanKeyletOpt;
|
||||||
|
|
||||||
|
LoanParameters const loanParams{
|
||||||
|
.account = lender,
|
||||||
|
.counter = borrower,
|
||||||
|
.principalRequest = Number{100},
|
||||||
|
.interest = TenthBips32{1922},
|
||||||
|
.payTotal = 5816,
|
||||||
|
.payInterval = 86400 * 6,
|
||||||
|
.gracePd = 86400 * 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
env(loanParams(env, broker));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// Wait for loan to be late enough to default
|
||||||
|
env.close(std::chrono::seconds(86400 * 40)); // 40 days
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const vaultSle = env.le(vaultKeylet);
|
||||||
|
Number assetsTotal = vaultSle->at(sfAssetsTotal);
|
||||||
|
Number assetsAvail = vaultSle->at(sfAssetsAvailable);
|
||||||
|
|
||||||
|
log << "After loan creation:" << std::endl;
|
||||||
|
log << " AssetsTotal: " << assetsTotal << std::endl;
|
||||||
|
log << " AssetsAvailable: " << assetsAvail << std::endl;
|
||||||
|
log << " Difference: " << (assetsTotal - assetsAvail) << std::endl;
|
||||||
|
|
||||||
|
auto const loanSle = env.le(loanKeylet);
|
||||||
|
if (!BEAST_EXPECT(loanSle))
|
||||||
|
return;
|
||||||
|
auto const state = calculateRoundedLoanState(loanSle);
|
||||||
|
|
||||||
|
log << "Loan state:" << std::endl;
|
||||||
|
log << " ValueOutstanding: " << state.valueOutstanding
|
||||||
|
<< std::endl;
|
||||||
|
log << " PrincipalOutstanding: " << state.principalOutstanding
|
||||||
|
<< std::endl;
|
||||||
|
log << " InterestOutstanding: " << state.interestOutstanding()
|
||||||
|
<< std::endl;
|
||||||
|
log << " InterestDue: " << state.interestDue << std::endl;
|
||||||
|
log << " FeeDue: " << state.managementFeeDue << std::endl;
|
||||||
|
|
||||||
|
// after loan creation the assets total and available should
|
||||||
|
// reflect the value of the loan
|
||||||
|
BEAST_EXPECT(assetsAvail < assetsTotal);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
assetsAvail ==
|
||||||
|
broker
|
||||||
|
.asset(
|
||||||
|
brokerParams.vaultDeposit - loanParams.principalRequest)
|
||||||
|
.number());
|
||||||
|
BEAST_EXPECT(
|
||||||
|
assetsTotal ==
|
||||||
|
broker.asset(brokerParams.vaultDeposit + state.interestDue)
|
||||||
|
.number());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Trigger default (dust adjustment will occur)
|
||||||
|
env(jtx::loan::manage(lender, loanKeylet.key, tfLoanDefault));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// Step 8: Verify phantom assets created
|
||||||
|
{
|
||||||
|
auto const vaultSle2 = env.le(vaultKeylet);
|
||||||
|
Number assetsTotal2 = vaultSle2->at(sfAssetsTotal);
|
||||||
|
Number assetsAvail2 = vaultSle2->at(sfAssetsAvailable);
|
||||||
|
|
||||||
|
log << "After default:" << std::endl;
|
||||||
|
log << " AssetsTotal: " << assetsTotal2 << std::endl;
|
||||||
|
log << " AssetsAvailable: " << assetsAvail2 << std::endl;
|
||||||
|
log << " Difference: " << (assetsTotal2 - assetsAvail2)
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
// after a default the assets total and available should be equal
|
||||||
|
BEAST_EXPECT(assetsAvail2 == assetsTotal2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
@@ -5647,6 +5803,7 @@ public:
|
|||||||
testPoC_UnsignedUnderflowOnFullPayAfterEarlyPeriodic();
|
testPoC_UnsignedUnderflowOnFullPayAfterEarlyPeriodic();
|
||||||
testLoanCoverMinimumRoundingExploit();
|
testLoanCoverMinimumRoundingExploit();
|
||||||
#endif
|
#endif
|
||||||
|
testDustManipulation();
|
||||||
|
|
||||||
testIssuerLoan();
|
testIssuerLoan();
|
||||||
testDisabled();
|
testDisabled();
|
||||||
|
|||||||
Reference in New Issue
Block a user