mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-28 17:40:25 +00:00
Merge branch 'develop' into tapanito/unit-tests
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
@@ -555,11 +556,11 @@ private:
|
||||
|
||||
{
|
||||
// bad preflight1
|
||||
json::Value jv = json::ObjectValue;
|
||||
json::Value jv = json::ValueType::Object;
|
||||
jv[jss::Account] = alice_.human();
|
||||
jv[jss::TransactionType] = jss::AMMDeposit;
|
||||
jv[jss::Asset] = STIssue(sfAsset, XRP).getJson(JsonOptions::KNone);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, USD).getJson(JsonOptions::KNone);
|
||||
jv[jss::Asset] = STIssue(sfAsset, XRP).getJson(JsonOptions::Values::None);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, USD).getJson(JsonOptions::Values::None);
|
||||
jv[jss::Fee] = "-1";
|
||||
env(jv, Ter(temBAD_FEE));
|
||||
}
|
||||
@@ -570,12 +571,12 @@ private:
|
||||
alice_, IOUAmount{-1}, std::nullopt, std::nullopt, Ter(temBAD_AMM_TOKENS));
|
||||
|
||||
{
|
||||
json::Value jv = json::ObjectValue;
|
||||
json::Value jv = json::ValueType::Object;
|
||||
jv[jss::Account] = alice_.human();
|
||||
jv[jss::TransactionType] = jss::AMMDeposit;
|
||||
jv[jss::Asset] = STIssue(sfAsset, XRP).getJson(JsonOptions::KNone);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, USD).getJson(JsonOptions::KNone);
|
||||
jv[jss::LPTokenOut] = USD(100).value().getJson(JsonOptions::KNone);
|
||||
jv[jss::Asset] = STIssue(sfAsset, XRP).getJson(JsonOptions::Values::None);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, USD).getJson(JsonOptions::Values::None);
|
||||
jv[jss::LPTokenOut] = USD(100).value().getJson(JsonOptions::Values::None);
|
||||
jv[jss::Flags] = tfLPToken;
|
||||
env(jv, Ter(temBAD_AMM_TOKENS));
|
||||
}
|
||||
@@ -2733,18 +2734,17 @@ private:
|
||||
|
||||
// 1st Interval after close, price for 0th interval.
|
||||
env(ammAlice.bid({.account = bob_}));
|
||||
env.close(seconds(kAUCTION_SLOT_INTERVAL_DURATION + 1));
|
||||
env.close(seconds(kAuctionSlotIntervalDuration + 1));
|
||||
BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 1, IOUAmount{1'155, -1}));
|
||||
|
||||
// 10th Interval after close, price for 1st interval.
|
||||
env(ammAlice.bid({.account = carol_}));
|
||||
env.close(seconds((10 * kAUCTION_SLOT_INTERVAL_DURATION) + 1));
|
||||
env.close(seconds((10 * kAuctionSlotIntervalDuration) + 1));
|
||||
BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 10, IOUAmount{121'275, -3}));
|
||||
|
||||
// 20th Interval (expired) after close, price for 10th interval.
|
||||
env(ammAlice.bid({.account = bob_}));
|
||||
env.close(
|
||||
seconds((kAUCTION_SLOT_TIME_INTERVALS * kAUCTION_SLOT_INTERVAL_DURATION) + 1));
|
||||
env.close(seconds((kAuctionSlotTimeIntervals * kAuctionSlotIntervalDuration) + 1));
|
||||
BEAST_EXPECT(ammAlice.expectAuctionSlot(0, std::nullopt, IOUAmount{127'33875, -5}));
|
||||
|
||||
// 0 Interval.
|
||||
@@ -2971,7 +2971,7 @@ private:
|
||||
ammTokens));
|
||||
}
|
||||
// Auction slot expired, no discounted fee
|
||||
env.close(seconds(kTOTAL_TIME_SLOT_SECS + 1));
|
||||
env.close(seconds(kTotalTimeSlotSecs + 1));
|
||||
// clock is parent's based
|
||||
env.close();
|
||||
if (!features[fixAMMv1_1])
|
||||
@@ -3060,7 +3060,7 @@ private:
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
// Bid a tiny amount
|
||||
auto const tiny = Number{STAmount::kMIN_VALUE, STAmount::kMIN_OFFSET};
|
||||
auto const tiny = Number{STAmount::kMinValue, STAmount::kMinOffset};
|
||||
env(ammAlice.bid({.account = alice_, .bidMin = IOUAmount{tiny}}));
|
||||
// Auction slot purchase price is equal to the tiny amount
|
||||
// since the minSlotPrice is 0 with no trading fee.
|
||||
@@ -3070,7 +3070,7 @@ private:
|
||||
// Bid the tiny amount
|
||||
env(ammAlice.bid({
|
||||
.account = alice_,
|
||||
.bidMin = IOUAmount{STAmount::kMIN_VALUE, STAmount::kMIN_OFFSET},
|
||||
.bidMin = IOUAmount{STAmount::kMinValue, STAmount::kMinOffset},
|
||||
}));
|
||||
// Pay slightly higher price
|
||||
BEAST_EXPECT(ammAlice.expectAuctionSlot(0, 0, IOUAmount{tiny * Number{105, -2}}));
|
||||
@@ -3228,9 +3228,9 @@ private:
|
||||
testAMM([&](AMM& ammAlice, Env& env) {
|
||||
auto const baseFee = env.current()->fees().base;
|
||||
env(escrow::create(carol_, ammAlice.ammAccount(), XRP(1)),
|
||||
escrow::kCONDITION(escrow::kCB1),
|
||||
escrow::kFINISH_TIME(env.now() + 1s),
|
||||
escrow::kCANCEL_TIME(env.now() + 2s),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kFinishTime(env.now() + 1s),
|
||||
escrow::kCancelTime(env.now() + 2s),
|
||||
Fee(baseFee * 150),
|
||||
Ter(tecNO_PERMISSION));
|
||||
});
|
||||
@@ -5102,7 +5102,7 @@ private:
|
||||
all);
|
||||
fund(env, gw_, {alice_}, XRP(20'000), {USD(10'000)});
|
||||
AMM amm(env, gw_, XRP(10'000), USD(10'000));
|
||||
for (auto i = 0; i < kMAX_DELETABLE_AMM_TRUST_LINES + 10; ++i)
|
||||
for (auto i = 0; i < kMaxDeletableAmmTrustLines + 10; ++i)
|
||||
{
|
||||
Account const a{std::to_string(i)};
|
||||
env.fund(XRP(1'000), a);
|
||||
@@ -5160,7 +5160,7 @@ private:
|
||||
all);
|
||||
fund(env, gw_, {alice_}, XRP(20'000), {USD(10'000)});
|
||||
AMM amm(env, gw_, XRP(10'000), USD(10'000));
|
||||
for (auto i = 0; i < (kMAX_DELETABLE_AMM_TRUST_LINES * 2) + 10; ++i)
|
||||
for (auto i = 0; i < (kMaxDeletableAmmTrustLines * 2) + 10; ++i)
|
||||
{
|
||||
Account const a{std::to_string(i)};
|
||||
env.fund(XRP(1'000), a);
|
||||
@@ -5218,7 +5218,8 @@ private:
|
||||
fail();
|
||||
}
|
||||
amm.deposit(carol_, 1'000);
|
||||
auto affected = env.meta()->getJson(JsonOptions::KNone)[sfAffectedNodes.fieldName];
|
||||
auto affected =
|
||||
env.meta()->getJson(JsonOptions::Values::None)[sfAffectedNodes.fieldName];
|
||||
try
|
||||
{
|
||||
bool found = false;
|
||||
@@ -6729,9 +6730,9 @@ private:
|
||||
AccountID const accountId = xrpl::pseudoAccountAddress(*env.current(), keylet.key);
|
||||
|
||||
env(pay(env.master.id(), accountId, XRP(1000)),
|
||||
Seq(kAUTOFILL),
|
||||
Fee(kAUTOFILL),
|
||||
Sig(kAUTOFILL));
|
||||
Seq(kAutofill),
|
||||
Fee(kAutofill),
|
||||
Sig(kAutofill));
|
||||
}
|
||||
|
||||
AMM const ammAlice(
|
||||
@@ -7271,6 +7272,95 @@ private:
|
||||
BEAST_EXPECT(env.balance(trader, shareIssue) == STAmount(shareIssue, std::uint64_t{0}));
|
||||
}
|
||||
|
||||
void
|
||||
testStaleAuthAccountsAfterReinit(FeatureBitset features)
|
||||
{
|
||||
testcase("Test AuthAccounts reset after empty pool reinitialization");
|
||||
using namespace jtx;
|
||||
|
||||
Env env(
|
||||
*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->FEES.reference_fee = XRPAmount(1);
|
||||
return cfg;
|
||||
}),
|
||||
features);
|
||||
Account const dan("dan");
|
||||
Account const ed("ed");
|
||||
fund(env, gw_, {alice_, carol_, bob_, dan, ed}, XRP(50'000), {USD(50'000)});
|
||||
AMM amm(env, alice_, XRP(10'000), USD(10'000));
|
||||
// Create excess trustlines to prevent AMM auto-deletion on withdrawal.
|
||||
for (auto i = 0; i < kMaxDeletableAmmTrustLines + 10; ++i)
|
||||
{
|
||||
Account const a{std::to_string(i)};
|
||||
env.fund(XRP(1'000), a);
|
||||
env(trust(a, STAmount{amm.lptIssue(), 10'000}));
|
||||
env.close();
|
||||
}
|
||||
// Carol deposits so she has LP tokens to bid.
|
||||
amm.deposit(carol_, 1'000'000);
|
||||
// Carol wins the auction slot, authorizing bob and dan.
|
||||
env(amm.bid({
|
||||
.account = carol_,
|
||||
.bidMin = 100,
|
||||
.authAccounts = {bob_, dan},
|
||||
}));
|
||||
env.close();
|
||||
BEAST_EXPECT(amm.expectAuctionSlot({bob_.id(), dan.id()}));
|
||||
// Withdraw all — AMM enters empty state but is not deleted because
|
||||
// excess trustlines prevent auto-deletion.
|
||||
amm.withdrawAll(alice_);
|
||||
amm.withdrawAll(carol_);
|
||||
BEAST_EXPECT(amm.ammExists());
|
||||
// Pre-conditions before re-init: AMM is empty and stale sfAuthAccounts
|
||||
// from carol's bid are still present.
|
||||
BEAST_EXPECT(amm.getLPTokensBalance() == IOUAmount{0});
|
||||
BEAST_EXPECT(amm.expectAuctionSlot({bob_.id(), dan.id()}));
|
||||
// Ed re-initializes the AMM via tfTwoAssetIfEmpty with fee=500.
|
||||
amm.deposit(
|
||||
ed,
|
||||
std::nullopt,
|
||||
XRP(10'000),
|
||||
USD(10'000),
|
||||
std::nullopt,
|
||||
tfTwoAssetIfEmpty,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
500);
|
||||
|
||||
auto const ammSle = env.current()->read(keylet::amm(amm[0], amm[1]));
|
||||
BEAST_EXPECT(ammSle && ammSle->isFieldPresent(sfAuctionSlot));
|
||||
auto const& slot = safeDowncast<STObject const&>(ammSle->peekAtField(sfAuctionSlot));
|
||||
|
||||
// sfDiscountedFee = 500 / AUCTION_SLOT_DISCOUNTED_FEE_FRACTION = 50,
|
||||
// sfPrice = 0 (reset on init), time interval = 0 (freshly issued slot).
|
||||
BEAST_EXPECT(amm.expectAuctionSlot(50, 0, IOUAmount{0}));
|
||||
// sfAccount must be the re-initializing depositor, not the previous
|
||||
// slot holder (carol).
|
||||
BEAST_EXPECT(slot[sfAccount] == ed.id());
|
||||
// sfTradingFee on the AMM SLE must reflect ed's deposit fee.
|
||||
BEAST_EXPECT(ammSle->getFieldU16(sfTradingFee) == 500);
|
||||
// sfVoteSlots must be reset to a single entry for ed.
|
||||
auto const& votes = ammSle->getFieldArray(sfVoteSlots);
|
||||
BEAST_EXPECT(votes.size() == 1);
|
||||
if (!votes.empty())
|
||||
{
|
||||
BEAST_EXPECT(votes[0].getAccountID(sfAccount) == ed.id());
|
||||
BEAST_EXPECT(votes[0].getFieldU16(sfTradingFee) == 500);
|
||||
BEAST_EXPECT(votes[0].getFieldU32(sfVoteWeight) == kVoteWeightScaleFactor);
|
||||
}
|
||||
// sfAuthAccounts behaviour depends on the fix.
|
||||
if (features[fixCleanup3_2_0])
|
||||
{
|
||||
BEAST_EXPECT(!slot.isFieldPresent(sfAuthAccounts));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
slot.isFieldPresent(sfAuthAccounts) && !slot.getFieldArray(sfAuthAccounts).empty());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -7343,6 +7433,8 @@ private:
|
||||
testWithdrawRounding(all);
|
||||
testWithdrawRounding(all - fixAMMv1_3);
|
||||
testFailedPseudoAccount();
|
||||
testStaleAuthAccountsAfterReinit(all);
|
||||
testStaleAuthAccountsAfterReinit(all - fixCleanup3_2_0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user