mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 01:06:48 +00:00
add reserve checks for SponsorTransfer
This commit is contained in:
@@ -53,7 +53,6 @@ struct Fees
|
||||
bool isAccountSponsored = false,
|
||||
std::size_t sponsoringAccountCount = 0) const
|
||||
{
|
||||
// return reserve + ownerCount * increment;
|
||||
return (isAccountSponsored ? XRPAmount(0) : reserve) +
|
||||
increment *
|
||||
(ownerCount + sponsoringOwnerCount - sponsoredOwnerCount) +
|
||||
|
||||
@@ -63,7 +63,17 @@ public:
|
||||
Account const alice("alice");
|
||||
Account const sponsor1("sponsor1");
|
||||
Account const sponsor2("sponsor2");
|
||||
env.fund(XRP(10000), alice, sponsor1, sponsor2);
|
||||
env.fund(XRP(10000), alice);
|
||||
env.fund(env.current()->fees().reserve * 2 - 1, sponsor1, sponsor2);
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice),
|
||||
sponsor::as(sponsor1, tfSponsorReserve),
|
||||
sponsor::sig(sponsor1),
|
||||
ter(tecINSUFFICIENT_RESERVE));
|
||||
|
||||
env(pay(alice, sponsor1, drops(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice),
|
||||
sponsor::as(sponsor1, tfSponsorReserve),
|
||||
@@ -81,6 +91,14 @@ public:
|
||||
BEAST_EXPECT(sle1->getAccountID(sfSponsorAccount) == sponsor1.id());
|
||||
|
||||
// transfer sponsor
|
||||
env(sponsor::transfer(alice),
|
||||
sponsor::as(sponsor2, tfSponsorReserve),
|
||||
sponsor::sig(sponsor2),
|
||||
ter(tecINSUFFICIENT_RESERVE));
|
||||
|
||||
env(pay(alice, sponsor2, drops(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice),
|
||||
sponsor::as(sponsor2, tfSponsorReserve),
|
||||
sponsor::sig(sponsor2));
|
||||
@@ -100,6 +118,21 @@ public:
|
||||
BEAST_EXPECT(sle2->getAccountID(sfSponsorAccount) == sponsor2.id());
|
||||
|
||||
// dissolve sponsor
|
||||
env(pay(alice,
|
||||
sponsor2,
|
||||
(env.balance(alice).value() -
|
||||
env.current()->fees().reserve - XRP(1) + drops(1))),
|
||||
fee(XRP(1)));
|
||||
env.close();
|
||||
|
||||
env.require(
|
||||
balance(alice, env.current()->fees().reserve - drops(1)));
|
||||
env(sponsor::transfer(alice), ter(tecINSUFFICIENT_RESERVE));
|
||||
env.close();
|
||||
|
||||
env(pay(sponsor2, alice, XRP(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice));
|
||||
env.close();
|
||||
|
||||
@@ -122,7 +155,13 @@ public:
|
||||
Account const bob("bob");
|
||||
Account const sponsor1("sponsor1");
|
||||
Account const sponsor2("sponsor2");
|
||||
env.fund(XRP(10000), alice, bob, sponsor1, sponsor2);
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.fund(
|
||||
env.current()->fees().reserve +
|
||||
env.current()->fees().increment - drops(1),
|
||||
sponsor1,
|
||||
sponsor2);
|
||||
env.close();
|
||||
|
||||
auto const seq = env.seq(alice);
|
||||
env(check::create(alice, bob, XRP(1)));
|
||||
@@ -131,6 +170,15 @@ public:
|
||||
auto const checkId = keylet::check(alice, seq).key;
|
||||
BEAST_EXPECT(env.le(keylet::unchecked(checkId)) != nullptr);
|
||||
|
||||
env(sponsor::transfer(alice, checkId),
|
||||
sponsor::as(sponsor1, tfSponsorReserve),
|
||||
sponsor::sig(sponsor1),
|
||||
ter(tecINSUFFICIENT_RESERVE));
|
||||
env.close();
|
||||
|
||||
env(pay(alice, sponsor1, drops(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice, checkId),
|
||||
sponsor::as(sponsor1, tfSponsorReserve),
|
||||
sponsor::sig(sponsor1));
|
||||
@@ -148,6 +196,14 @@ public:
|
||||
BEAST_EXPECT(sle1->getAccountID(sfSponsorAccount) == sponsor1.id());
|
||||
|
||||
// transfer sponsor
|
||||
env(sponsor::transfer(alice, checkId),
|
||||
sponsor::as(sponsor2, tfSponsorReserve),
|
||||
sponsor::sig(sponsor2),
|
||||
ter(tecINSUFFICIENT_RESERVE));
|
||||
|
||||
env(pay(alice, sponsor2, drops(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice, checkId),
|
||||
sponsor::as(sponsor2, tfSponsorReserve),
|
||||
sponsor::sig(sponsor2));
|
||||
@@ -167,6 +223,21 @@ public:
|
||||
BEAST_EXPECT(sle2->getAccountID(sfSponsorAccount) == sponsor2.id());
|
||||
|
||||
// dissolve sponsor
|
||||
env(pay(alice,
|
||||
sponsor2,
|
||||
(env.balance(alice).value() -
|
||||
env.current()->fees().reserve -
|
||||
env.current()->fees().increment - XRP(1) + drops(1))),
|
||||
fee(XRP(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice, checkId),
|
||||
ter(tecINSUFFICIENT_RESERVE));
|
||||
env.close();
|
||||
|
||||
env(pay(sponsor2, alice, XRP(1)));
|
||||
env.close();
|
||||
|
||||
env(sponsor::transfer(alice, checkId));
|
||||
env.close();
|
||||
|
||||
|
||||
@@ -111,8 +111,15 @@ TER
|
||||
SponsorTransfer::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
auto const index = ctx.tx[~sfLedgerIndex];
|
||||
auto const newSponsor = getTxReserveSponsor(ctx.view, ctx.tx);
|
||||
|
||||
if (index)
|
||||
bool const isObjectSponsor = index != std::nullopt;
|
||||
|
||||
auto const accSle = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
|
||||
if (!accSle)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (isObjectSponsor)
|
||||
{
|
||||
auto const sle = ctx.view.read(keylet::unchecked(*index));
|
||||
if (!sle)
|
||||
@@ -123,33 +130,64 @@ SponsorTransfer::preclaim(PreclaimContext const& ctx)
|
||||
if (!owner)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
if (sle->isFieldPresent(sfSponsorAccount))
|
||||
if (newSponsor)
|
||||
{
|
||||
auto const sponsor = sle->getAccountID(sfSponsorAccount);
|
||||
if (sponsor == owner)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// TODO: check reserve
|
||||
if (sle->isFieldPresent(sfSponsorAccount))
|
||||
{
|
||||
// transfer sponsor
|
||||
if ((*newSponsor)->getAccountID(sfAccount) == owner)
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check reserve
|
||||
// dissolve sponsor
|
||||
// check object is sponsored
|
||||
if (!sle->isFieldPresent(sfSponsorAccount))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
// check account have sufficient balance
|
||||
if (auto const ter = checkInsufficientReserve(
|
||||
ctx.view,
|
||||
accSle,
|
||||
accSle->getFieldAmount(sfBalance),
|
||||
newSponsor,
|
||||
// TODO: address variable ownerCount like PriceOracle
|
||||
1);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const accSle = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
|
||||
if (!accSle)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (accSle->isFieldPresent(sfSponsorAccount))
|
||||
if (newSponsor)
|
||||
{
|
||||
// TODO: check reserve
|
||||
if (accSle->isFieldPresent(sfSponsorAccount))
|
||||
{
|
||||
// check not same account
|
||||
if ((*newSponsor)->getAccountID(sfAccount) ==
|
||||
accSle->getAccountID(sfAccount))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check reserve
|
||||
// dissolve sponsor
|
||||
// check account is sponsored
|
||||
if (!accSle->isFieldPresent(sfSponsorAccount))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
// check account have sufficient balance
|
||||
if (auto const ter = checkInsufficientReserve(
|
||||
ctx.view,
|
||||
accSle,
|
||||
accSle->getFieldAmount(sfBalance),
|
||||
newSponsor,
|
||||
0,
|
||||
1);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -161,12 +199,13 @@ SponsorTransfer::doApply()
|
||||
auto const& tx = ctx_.tx;
|
||||
|
||||
auto const index = tx[~sfLedgerIndex];
|
||||
bool const isObjectSponsor = index != std::nullopt;
|
||||
|
||||
auto const accSle = view().peek(keylet::account(account_));
|
||||
if (!accSle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (index)
|
||||
if (isObjectSponsor)
|
||||
{
|
||||
// transfer object sponsor
|
||||
auto const objSle = view().peek(keylet::unchecked(*index));
|
||||
|
||||
@@ -458,7 +458,8 @@ checkInsufficientReserve(
|
||||
std::shared_ptr<SLE const> accSle,
|
||||
STAmount const& accBalance,
|
||||
std::optional<std::shared_ptr<SLE const>> const& _sponsorSle,
|
||||
std::int32_t ownerCountDelta);
|
||||
std::int32_t ownerCountDelta,
|
||||
std::int32_t accountCountDelta = 0);
|
||||
|
||||
std::optional<std::shared_ptr<SLE>>
|
||||
getTxReserveSponsor(ApplyView& view, STTx const& tx);
|
||||
|
||||
@@ -1027,7 +1027,8 @@ checkInsufficientReserve(
|
||||
std::shared_ptr<SLE const> accSle,
|
||||
STAmount const& accBalance,
|
||||
std::optional<std::shared_ptr<SLE const>> const& _sponsorSle,
|
||||
std::int32_t ownerCountDelta)
|
||||
std::int32_t ownerCountDelta,
|
||||
std::int32_t accountCountDelta)
|
||||
{
|
||||
if (_sponsorSle.has_value())
|
||||
{
|
||||
@@ -1037,8 +1038,9 @@ checkInsufficientReserve(
|
||||
sponsorSle->getFieldU32(sfOwnerCount),
|
||||
sponsorSle->getFieldU32(sfSponsoredOwnerCount),
|
||||
sponsorSle->getFieldU32(sfSponsoringOwnerCount) + ownerCountDelta,
|
||||
sponsorSle->isFieldPresent(sfSponsor),
|
||||
sponsorSle->getFieldU32(sfSponsoringAccountCount))};
|
||||
sponsorSle->isFieldPresent(sfSponsorAccount),
|
||||
sponsorSle->getFieldU32(sfSponsoringAccountCount) +
|
||||
accountCountDelta)};
|
||||
|
||||
if (sponsorBalance < sponsorReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
@@ -1049,8 +1051,8 @@ checkInsufficientReserve(
|
||||
accSle->getFieldU32(sfOwnerCount) + ownerCountDelta,
|
||||
accSle->getFieldU32(sfSponsoredOwnerCount),
|
||||
accSle->getFieldU32(sfSponsoringOwnerCount),
|
||||
accSle->isFieldPresent(sfSponsor),
|
||||
accSle->getFieldU32(sfSponsoringAccountCount))};
|
||||
accSle->isFieldPresent(sfSponsorAccount),
|
||||
accSle->getFieldU32(sfSponsoringAccountCount) + accountCountDelta)};
|
||||
|
||||
if (accBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
Reference in New Issue
Block a user