mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 09:16:47 +00:00
check reserve
This commit is contained in:
@@ -46,9 +46,18 @@ struct Fees
|
||||
the reserve increment times the number of increments.
|
||||
*/
|
||||
XRPAmount
|
||||
accountReserve(std::size_t ownerCount) const
|
||||
accountReserve(
|
||||
std::size_t ownerCount,
|
||||
std::size_t sponsoredOwnerCount = 0,
|
||||
std::size_t sponsoringOwnerCount = 0,
|
||||
bool isAccountSponsored = false,
|
||||
std::size_t sponsoringAccountCount = 0) const
|
||||
{
|
||||
return reserve + ownerCount * increment;
|
||||
// return reserve + ownerCount * increment;
|
||||
return (isAccountSponsored ? XRPAmount(0) : reserve) +
|
||||
increment *
|
||||
(ownerCount + sponsoringOwnerCount - sponsoredOwnerCount) +
|
||||
reserve * sponsoringAccountCount;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/check.h>
|
||||
#include <test/jtx/did.h>
|
||||
#include <test/jtx/sponsor.h>
|
||||
@@ -99,7 +100,20 @@ public:
|
||||
Account const bob("bob");
|
||||
Account const sponsor("sponsor");
|
||||
|
||||
env.fund(XRP(10000), alice, bob, sponsor);
|
||||
auto const reserve = env.current()->fees().reserve;
|
||||
auto const increment = env.current()->fees().increment;
|
||||
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.fund(drops(reserve) + drops(increment) - drops(1), sponsor);
|
||||
|
||||
// check sponsor balance
|
||||
env(check::create(alice, bob, XRP(1)),
|
||||
sponsor::as(sponsor, tfSponsorReserve),
|
||||
sponsor::sig(sponsor),
|
||||
ter(tecINSUFFICIENT_RESERVE));
|
||||
|
||||
env(pay(alice, sponsor, drops(1)));
|
||||
env.close();
|
||||
|
||||
// CheckCreate
|
||||
auto const seq = env.seq(alice);
|
||||
|
||||
@@ -192,6 +192,7 @@ AMMClawback::applyGuts(Sandbox& sb)
|
||||
std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) =
|
||||
AMMWithdraw::equalWithdrawTokens(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
*ammSle,
|
||||
holder,
|
||||
ammAccount,
|
||||
@@ -273,6 +274,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
|
||||
// tfee is actually not used, so pass tfee as 0.
|
||||
return AMMWithdraw::equalWithdrawTokens(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
ammSle,
|
||||
holder,
|
||||
ammAccount,
|
||||
@@ -308,6 +310,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
|
||||
|
||||
return AMMWithdraw::withdraw(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
holder,
|
||||
@@ -327,6 +330,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
|
||||
// tfee is actually not used, so pass tfee as 0.
|
||||
return AMMWithdraw::withdraw(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
holder,
|
||||
|
||||
@@ -339,6 +339,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
|
||||
if (subTxType & tfTwoAsset)
|
||||
return equalWithdrawLimit(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
*ammSle,
|
||||
ammAccountID,
|
||||
amountBalance,
|
||||
@@ -350,6 +351,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
|
||||
if (subTxType & tfOneAssetLPToken || subTxType & tfOneAssetWithdrawAll)
|
||||
return singleWithdrawTokens(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
*ammSle,
|
||||
ammAccountID,
|
||||
amountBalance,
|
||||
@@ -360,6 +362,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
|
||||
if (subTxType & tfLimitLPToken)
|
||||
return singleWithdrawEPrice(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
*ammSle,
|
||||
ammAccountID,
|
||||
amountBalance,
|
||||
@@ -370,6 +373,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
|
||||
if (subTxType & tfSingleAsset)
|
||||
return singleWithdraw(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
*ammSle,
|
||||
ammAccountID,
|
||||
amountBalance,
|
||||
@@ -380,6 +384,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
|
||||
{
|
||||
return equalWithdrawTokens(
|
||||
sb,
|
||||
ctx_.tx,
|
||||
*ammSle,
|
||||
ammAccountID,
|
||||
amountBalance,
|
||||
@@ -435,6 +440,7 @@ AMMWithdraw::doApply()
|
||||
std::pair<TER, STAmount>
|
||||
AMMWithdraw::withdraw(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -448,6 +454,7 @@ AMMWithdraw::withdraw(
|
||||
STAmount newLPTokenBalance;
|
||||
std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) = withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
account_,
|
||||
@@ -467,6 +474,7 @@ AMMWithdraw::withdraw(
|
||||
std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
||||
AMMWithdraw::withdraw(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
AccountID const& account,
|
||||
@@ -591,13 +599,18 @@ AMMWithdraw::withdraw(
|
||||
auto const balance = (*sleAccount)[sfBalance].xrp();
|
||||
std::uint32_t const ownerCount = sleAccount->at(sfOwnerCount);
|
||||
|
||||
// See also SetTrust::doApply()
|
||||
XRPAmount const reserve(
|
||||
(ownerCount < 2) ? XRPAmount(beast::zero)
|
||||
: view.fees().accountReserve(ownerCount + 1));
|
||||
|
||||
if (std::max(priorBalance, balance) < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
if (ownerCount >= 2)
|
||||
{
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view,
|
||||
sleAccount,
|
||||
std::max(priorBalance, balance),
|
||||
sponsor,
|
||||
1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
};
|
||||
@@ -685,6 +698,7 @@ adjustLPTokensIn(
|
||||
std::pair<TER, STAmount>
|
||||
AMMWithdraw::equalWithdrawTokens(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -699,6 +713,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) =
|
||||
equalWithdrawTokens(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
account_,
|
||||
ammAccount,
|
||||
@@ -749,6 +764,7 @@ AMMWithdraw::deleteAMMAccountIfEmpty(
|
||||
std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
||||
AMMWithdraw::equalWithdrawTokens(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const account,
|
||||
AccountID const& ammAccount,
|
||||
@@ -770,6 +786,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
{
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
account,
|
||||
@@ -805,6 +822,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
account,
|
||||
@@ -857,6 +875,7 @@ AMMWithdraw::equalWithdrawTokens(
|
||||
std::pair<TER, STAmount>
|
||||
AMMWithdraw::equalWithdrawLimit(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -881,6 +900,7 @@ AMMWithdraw::equalWithdrawLimit(
|
||||
{
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
amountBalance,
|
||||
@@ -914,6 +934,7 @@ AMMWithdraw::equalWithdrawLimit(
|
||||
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
amountBalance,
|
||||
@@ -932,6 +953,7 @@ AMMWithdraw::equalWithdrawLimit(
|
||||
std::pair<TER, STAmount>
|
||||
AMMWithdraw::singleWithdraw(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -958,6 +980,7 @@ AMMWithdraw::singleWithdraw(
|
||||
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
amountBalance,
|
||||
@@ -981,6 +1004,7 @@ AMMWithdraw::singleWithdraw(
|
||||
std::pair<TER, STAmount>
|
||||
AMMWithdraw::singleWithdrawTokens(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -1000,6 +1024,7 @@ AMMWithdraw::singleWithdrawTokens(
|
||||
{
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
amountBalance,
|
||||
@@ -1035,6 +1060,7 @@ AMMWithdraw::singleWithdrawTokens(
|
||||
std::pair<TER, STAmount>
|
||||
AMMWithdraw::singleWithdrawEPrice(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -1080,6 +1106,7 @@ AMMWithdraw::singleWithdrawEPrice(
|
||||
{
|
||||
return withdraw(
|
||||
view,
|
||||
tx,
|
||||
ammSle,
|
||||
ammAccount,
|
||||
amountBalance,
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
||||
equalWithdrawTokens(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const account,
|
||||
AccountID const& ammAccount,
|
||||
@@ -135,6 +136,7 @@ public:
|
||||
static std::tuple<TER, STAmount, STAmount, std::optional<STAmount>>
|
||||
withdraw(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
AccountID const& account,
|
||||
@@ -177,6 +179,7 @@ private:
|
||||
std::pair<TER, STAmount>
|
||||
withdraw(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -202,6 +205,7 @@ private:
|
||||
std::pair<TER, STAmount>
|
||||
equalWithdrawTokens(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -227,6 +231,7 @@ private:
|
||||
std::pair<TER, STAmount>
|
||||
equalWithdrawLimit(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -249,6 +254,7 @@ private:
|
||||
std::pair<TER, STAmount>
|
||||
singleWithdraw(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -270,6 +276,7 @@ private:
|
||||
std::pair<TER, STAmount>
|
||||
singleWithdrawTokens(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
@@ -292,6 +299,7 @@ private:
|
||||
std::pair<TER, STAmount>
|
||||
singleWithdrawEPrice(
|
||||
Sandbox& view,
|
||||
STTx const& tx,
|
||||
SLE const& ammSle,
|
||||
AccountID const& ammAccount,
|
||||
STAmount const& amountBalance,
|
||||
|
||||
@@ -368,8 +368,10 @@ CashCheck::doApply()
|
||||
auto const sleDst = psb.peek(keylet::account(account_));
|
||||
|
||||
// Can the account cover the trust line's reserve?
|
||||
if (std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
|
||||
mPriorBalance < psb.fees().accountReserve(ownerCount + 1))
|
||||
auto const sponsor = getTxReserveSponsor(psb, ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
psb, sleDst, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
JLOG(j_.trace()) << "Trust line does not exist. "
|
||||
"Insufficent reserve to create line.";
|
||||
|
||||
@@ -177,13 +177,11 @@ CreateCheck::doApply()
|
||||
// A check counts against the reserve of the issuing account, but we
|
||||
// check the starting balance because we want to allow dipping into the
|
||||
// reserve to pay fees.
|
||||
{
|
||||
STAmount const reserve{
|
||||
view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
|
||||
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(view(), sle, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Note that we use the value from the sequence or ticket as the
|
||||
// Check sequence. For more explanation see comments in SeqProxy.h.
|
||||
@@ -243,7 +241,6 @@ CreateCheck::doApply()
|
||||
sleCheck->setFieldU64(sfOwnerNode, *page);
|
||||
}
|
||||
// If we succeeded, the new entry counts against the creator's reserve.
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sle, sponsor, 1, viewJ);
|
||||
addSponsorToLedgerEntry(sleCheck, sponsor);
|
||||
return tesSUCCESS;
|
||||
|
||||
@@ -813,10 +813,10 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
||||
return {tefINTERNAL, false};
|
||||
|
||||
{
|
||||
XRPAmount reserve =
|
||||
sb.fees().accountReserve(sleCreator->getFieldU32(sfOwnerCount) + 1);
|
||||
|
||||
if (mPriorBalance < reserve)
|
||||
auto const sponsor = getTxReserveSponsor(sb, ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
sb, sleCreator, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
// If we are here, the signing account had an insufficient reserve
|
||||
// *prior* to our processing. If something actually crossed, then
|
||||
|
||||
@@ -91,13 +91,11 @@ CreateTicket::doApply()
|
||||
// check the starting balance because we want to allow dipping into the
|
||||
// reserve to pay fees.
|
||||
std::uint32_t const ticketCount = ctx_.tx[sfTicketCount];
|
||||
{
|
||||
XRPAmount const reserve = view().fees().accountReserve(
|
||||
sleAccountRoot->getFieldU32(sfOwnerCount) + ticketCount);
|
||||
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view(), sleAccountRoot, mPriorBalance, sponsor, ticketCount);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
beast::Journal viewJ{ctx_.app.journal("View")};
|
||||
|
||||
@@ -113,7 +111,6 @@ CreateTicket::doApply()
|
||||
txSeq != 0 && txSeq != (firstTicketSeq - 1))
|
||||
return tefINTERNAL;
|
||||
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
for (std::uint32_t i = 0; i < ticketCount; ++i)
|
||||
{
|
||||
std::uint32_t const curTicketSeq = firstTicketSeq + i;
|
||||
|
||||
@@ -148,12 +148,11 @@ CredentialCreate::doApply()
|
||||
if (!sleIssuer)
|
||||
return tefINTERNAL;
|
||||
|
||||
{
|
||||
STAmount const reserve{view().fees().accountReserve(
|
||||
sleIssuer->getFieldU32(sfOwnerCount) + 1)};
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view(), sleIssuer, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
sleCred->setAccountID(sfSubject, subject);
|
||||
sleCred->setAccountID(sfIssuer, account_);
|
||||
@@ -174,7 +173,6 @@ CredentialCreate::doApply()
|
||||
return tecDIR_FULL;
|
||||
sleCred->setFieldU64(sfIssuerNode, *page);
|
||||
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sleIssuer, sponsor, 1, j_);
|
||||
addSponsorToLedgerEntry(sleCred, sponsor);
|
||||
}
|
||||
@@ -372,12 +370,11 @@ CredentialAccept::doApply()
|
||||
if (!sleSubject || !sleIssuer)
|
||||
return tefINTERNAL;
|
||||
|
||||
{
|
||||
STAmount const reserve{view().fees().accountReserve(
|
||||
sleSubject->getFieldU32(sfOwnerCount) + 1)};
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view(), sleSubject, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const credType(ctx_.tx[sfCredentialType]);
|
||||
Keylet const credentialKey = keylet::credential(account_, issuer, credType);
|
||||
@@ -394,8 +391,7 @@ CredentialAccept::doApply()
|
||||
sleCred->setFieldU32(sfFlags, lsfAccepted);
|
||||
view().update(sleCred);
|
||||
|
||||
auto const currentSponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sleIssuer, currentSponsor, -1, j_);
|
||||
adjustOwnerCount(view(), sleIssuer, sponsor, -1, j_);
|
||||
auto const newSponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sleSubject, newSponsor, 1, j_);
|
||||
addSponsorToLedgerEntry(sleCred, newSponsor);
|
||||
|
||||
@@ -88,14 +88,12 @@ addSLE(
|
||||
return tefINTERNAL;
|
||||
|
||||
// Check reserve availability for new object creation
|
||||
{
|
||||
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
|
||||
auto const reserve =
|
||||
ctx.view().fees().accountReserve((*sleAccount)[sfOwnerCount] + 1);
|
||||
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(ctx.view(), ctx.tx);
|
||||
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx.view(), sleAccount, balance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Add ledger object to ledger
|
||||
ctx.view().insert(sle);
|
||||
@@ -108,7 +106,6 @@ addSLE(
|
||||
return tecDIR_FULL;
|
||||
(*sle)[sfOwnerNode] = *page;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(ctx.view(), ctx.tx);
|
||||
adjustOwnerCount(ctx.view(), sleAccount, sponsor, 1, ctx.journal);
|
||||
addSponsorToLedgerEntry(sle, sponsor);
|
||||
ctx.view().update(sleAccount);
|
||||
|
||||
@@ -99,11 +99,11 @@ DelegateSet::doApply()
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
STAmount const reserve{ctx_.view().fees().accountReserve(
|
||||
sleOwner->getFieldU32(sfOwnerCount) + 1)};
|
||||
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view(), sleOwner, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const& permissions = ctx_.tx.getFieldArray(sfPermissions);
|
||||
if (!permissions.empty())
|
||||
@@ -123,7 +123,6 @@ DelegateSet::doApply()
|
||||
|
||||
(*sle)[sfOwnerNode] = *page;
|
||||
ctx_.view().insert(sle);
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
adjustOwnerCount(ctx_.view(), sleOwner, sponsor, 1, ctx_.journal);
|
||||
addSponsorToLedgerEntry(sle, sponsor);
|
||||
}
|
||||
|
||||
@@ -173,13 +173,11 @@ DepositPreauth::doApply()
|
||||
// A preauth counts against the reserve of the issuing account, but we
|
||||
// check the starting balance because we want to allow dipping into the
|
||||
// reserve to pay fees.
|
||||
{
|
||||
STAmount const reserve{view().fees().accountReserve(
|
||||
sleOwner->getFieldU32(sfOwnerCount) + 1)};
|
||||
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view(), sleOwner, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Preclaim already verified that the Preauth entry does not yet exist.
|
||||
// Create and populate the Preauth entry.
|
||||
@@ -206,7 +204,6 @@ DepositPreauth::doApply()
|
||||
slePreauth->setFieldU64(sfOwnerNode, *page);
|
||||
|
||||
// If we succeeded, the new entry counts against the creator's reserve.
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sleOwner, sponsor, 1, j_);
|
||||
addSponsorToLedgerEntry(slePreauth, sponsor);
|
||||
}
|
||||
@@ -226,13 +223,11 @@ DepositPreauth::doApply()
|
||||
// A preauth counts against the reserve of the issuing account, but we
|
||||
// check the starting balance because we want to allow dipping into the
|
||||
// reserve to pay fees.
|
||||
{
|
||||
STAmount const reserve{view().fees().accountReserve(
|
||||
sleOwner->getFieldU32(sfOwnerCount) + 1)};
|
||||
|
||||
if (mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view(), sleOwner, mPriorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Preclaim already verified that the Preauth entry does not yet exist.
|
||||
// Create and populate the Preauth entry.
|
||||
@@ -272,7 +267,6 @@ DepositPreauth::doApply()
|
||||
slePreauth->setFieldU64(sfOwnerNode, *page);
|
||||
|
||||
// If we succeeded, the new entry counts against the creator's reserve.
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sleOwner, sponsor, 1, j_);
|
||||
addSponsorToLedgerEntry(slePreauth, sponsor);
|
||||
}
|
||||
|
||||
@@ -495,16 +495,21 @@ EscrowCreate::doApply()
|
||||
// Check reserve and funds availability
|
||||
STAmount const amount{ctx_.tx[sfAmount]};
|
||||
|
||||
auto const reserve =
|
||||
ctx_.view().fees().accountReserve((*sle)[sfOwnerCount] + 1);
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(), sle, mSourceBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (mSourceBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
// Check reserve and funds availability
|
||||
if (isXRP(amount))
|
||||
{
|
||||
if (mSourceBalance < reserve + STAmount(amount).xrp())
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(),
|
||||
sle,
|
||||
mSourceBalance - STAmount(amount).xrp(),
|
||||
std::optional<std::shared_ptr<SLE const>>(),
|
||||
1);
|
||||
!isTesSuccess(ret))
|
||||
return tecUNFUNDED;
|
||||
}
|
||||
|
||||
@@ -599,7 +604,6 @@ EscrowCreate::doApply()
|
||||
}
|
||||
|
||||
// increment owner count
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
adjustOwnerCount(ctx_.view(), sle, sponsor, 1, ctx_.journal);
|
||||
addSponsorToLedgerEntry(slep, sponsor);
|
||||
ctx_.view().update(sle);
|
||||
@@ -841,8 +845,10 @@ escrowUnlockApplyHelper<Issue>(
|
||||
if (!view.exists(trustLineKey) && createAsset && !receiverIssuer)
|
||||
{
|
||||
// Can the account cover the trust line's reserve?
|
||||
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
|
||||
xrpBalance < view.fees().accountReserve(ownerCount + 1))
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(view, sleDest, xrpBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
JLOG(journal.trace()) << "Trust line does not exist. "
|
||||
"Insufficent reserve to create line.";
|
||||
@@ -968,11 +974,11 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
|
||||
createAsset && !receiverIssuer)
|
||||
{
|
||||
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
|
||||
xrpBalance < view.fees().accountReserve(ownerCount + 1))
|
||||
{
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(view, sleDest, xrpBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (auto const ter =
|
||||
MPTokenAuthorize::createMPToken(view, mptID, receiver, 0);
|
||||
@@ -982,7 +988,6 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
}
|
||||
|
||||
// update owner count.
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
adjustOwnerCount(view, sleDest, sponsor, 1, journal);
|
||||
addSponsorToLedgerEntry(sleDest, sponsor);
|
||||
}
|
||||
|
||||
@@ -225,13 +225,14 @@ MPTokenAuthorize::authorize(
|
||||
// an account owns, in the case of MPTokens we only
|
||||
// *enforce* a reserve if the user owns more than two
|
||||
// items. This is similar to the reserve requirements of trust lines.
|
||||
std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount);
|
||||
XRPAmount const reserveCreate(
|
||||
(uOwnerCount < 2) ? XRPAmount(beast::zero)
|
||||
: view.fees().accountReserve(uOwnerCount + 1));
|
||||
|
||||
if (args.priorBalance < reserveCreate)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
if (sleAcct->getFieldU32(sfOwnerCount) >= 2)
|
||||
{
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view, sleAcct, args.priorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto const mptokenKey =
|
||||
keylet::mptoken(args.mptIssuanceID, args.account);
|
||||
@@ -245,7 +246,6 @@ MPTokenAuthorize::authorize(
|
||||
view.insert(mptoken);
|
||||
|
||||
// Update owner count.
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
adjustOwnerCount(view, sleAcct, sponsor, 1, journal);
|
||||
addSponsorToLedgerEntry(mptoken, sponsor);
|
||||
|
||||
|
||||
@@ -93,16 +93,18 @@ MPTokenIssuanceCreate::create(
|
||||
if (!acct)
|
||||
return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
||||
|
||||
if (args.priorBalance &&
|
||||
*(args.priorBalance) <
|
||||
view.fees().accountReserve((*acct)[sfOwnerCount] + 1))
|
||||
return Unexpected(tecINSUFFICIENT_RESERVE);
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
if (args.priorBalance)
|
||||
{
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
view, acct, *(args.priorBalance), sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return Unexpected(ret); // tecINSUFFICIENT_RESERVE
|
||||
}
|
||||
|
||||
auto const mptId = makeMptID(args.sequence, args.account);
|
||||
auto const mptIssuanceKeylet = keylet::mptIssuance(mptId);
|
||||
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
|
||||
// create the MPTokenIssuance
|
||||
{
|
||||
auto const ownerNode = view.dirInsert(
|
||||
|
||||
@@ -466,10 +466,13 @@ NFTokenAcceptOffer::transferNFToken(
|
||||
auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
|
||||
if (buyerOwnerCountAfter > buyerOwnerCountBefore)
|
||||
{
|
||||
if (auto const reserve =
|
||||
view().fees().accountReserve(buyerOwnerCountAfter);
|
||||
buyerBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = account_ == buyer
|
||||
? getTxReserveSponsor(ctx_.view(), ctx_.tx)
|
||||
: std::optional<std::shared_ptr<SLE const>>();
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(), sleBuyer, buyerBalance, sponsor, 0);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -352,9 +352,15 @@ NFTokenMint::doApply()
|
||||
view().read(keylet::account(account_))->getFieldU32(sfOwnerCount);
|
||||
ownerCountAfter > ownerCountBefore)
|
||||
{
|
||||
if (auto const reserve = view().fees().accountReserve(ownerCountAfter);
|
||||
mPriorBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(),
|
||||
view().read(keylet::account(account_)),
|
||||
mPriorBalance,
|
||||
sponsor,
|
||||
0);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -1044,12 +1044,14 @@ tokenOfferCreateApply(
|
||||
std::uint32_t txFlags)
|
||||
{
|
||||
Keylet const acctKeylet = keylet::account(acctID);
|
||||
if (auto const acct = view.read(acctKeylet);
|
||||
priorBalance < view.fees().accountReserve((*acct)[sfOwnerCount] + 1))
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const acct = view.read(acctKeylet);
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(view, acct, priorBalance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const offerID = keylet::nftoffer(acctID, seqProxy.value());
|
||||
auto const sponsor = getTxReserveSponsor(view, tx);
|
||||
|
||||
// Create the offer:
|
||||
{
|
||||
|
||||
@@ -204,13 +204,15 @@ PayChanCreate::preclaim(PreclaimContext const& ctx)
|
||||
// Check reserve and funds availability
|
||||
{
|
||||
auto const balance = (*sle)[sfBalance];
|
||||
auto const reserve =
|
||||
ctx.view.fees().accountReserve((*sle)[sfOwnerCount] + 1);
|
||||
auto const sponsor = getTxReserveSponsor(ctx.view, ctx.tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(ctx.view, sle, balance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
if (balance < reserve + ctx.tx[sfAmount])
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx.view, sle, balance - ctx.tx[sfAmount], sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return tecUNFUNDED;
|
||||
}
|
||||
|
||||
@@ -392,13 +394,19 @@ PayChanFund::doApply()
|
||||
{
|
||||
// Check reserve and funds availability
|
||||
auto const balance = (*sle)[sfBalance];
|
||||
auto const reserve =
|
||||
ctx_.view().fees().accountReserve((*sle)[sfOwnerCount]);
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(ctx_.view(), sle, balance, sponsor, 0);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
if (balance < reserve + ctx_.tx[sfAmount])
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(),
|
||||
sle,
|
||||
balance - ctx_.tx[sfAmount],
|
||||
std::optional<std::shared_ptr<SLE const>>(),
|
||||
0);
|
||||
!isTesSuccess(ret))
|
||||
return tecUNFUNDED;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,10 +121,11 @@ PermissionedDomainSet::doApply()
|
||||
// Create new permissioned domain.
|
||||
// Check reserve availability for new object creation
|
||||
auto const balance = STAmount((*ownerSle)[sfBalance]).xrp();
|
||||
auto const reserve =
|
||||
ctx_.view().fees().accountReserve((*ownerSle)[sfOwnerCount] + 1);
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(), ownerSle, balance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
Keylet const pdKeylet = keylet::permissionedDomain(
|
||||
account_, ctx_.tx.getFieldU32(sfSequence));
|
||||
@@ -142,7 +143,6 @@ PermissionedDomainSet::doApply()
|
||||
|
||||
slePd->setFieldU64(sfOwnerNode, *page);
|
||||
// If we succeeded, the new entry counts against the creator's reserve.
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), ownerSle, sponsor, 1, ctx_.journal);
|
||||
addSponsorToLedgerEntry(slePd, sponsor);
|
||||
view().insert(slePd);
|
||||
|
||||
@@ -172,12 +172,12 @@ SetOracle::preclaim(PreclaimContext const& ctx)
|
||||
if (pairs.size() > maxOracleDataSeries)
|
||||
return tecARRAY_TOO_LARGE;
|
||||
|
||||
auto const reserve = ctx.view.fees().accountReserve(
|
||||
sleSetter->getFieldU32(sfOwnerCount) + adjustReserve);
|
||||
auto const& balance = sleSetter->getFieldAmount(sfBalance);
|
||||
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(ctx.view, ctx.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx.view, sleSetter, balance, sponsor, adjustReserve);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -354,9 +354,6 @@ SetSignerList::replaceSignerList()
|
||||
if (!sle)
|
||||
return tefINTERNAL;
|
||||
|
||||
// Compute new reserve. Verify the account has funds to meet the reserve.
|
||||
std::uint32_t const oldOwnerCount{(*sle)[sfOwnerCount]};
|
||||
|
||||
// The required reserve changes based on featureMultiSignReserve...
|
||||
int addedOwnerCount{1};
|
||||
std::uint32_t flags{lsfOneOwnerCount};
|
||||
@@ -367,14 +364,14 @@ SetSignerList::replaceSignerList()
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
XRPAmount const newReserve{
|
||||
view().fees().accountReserve(oldOwnerCount + addedOwnerCount)};
|
||||
|
||||
// We check the reserve against the starting balance because we want to
|
||||
// allow dipping into the reserve to pay fees. This behavior is consistent
|
||||
// with CreateTicket.
|
||||
if (mPriorBalance < newReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(), sle, mPriorBalance, sponsor, addedOwnerCount);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Everything's ducky. Add the ltSIGNER_LIST to the ledger.
|
||||
auto signerList = std::make_shared<SLE>(signerListKeylet);
|
||||
@@ -396,7 +393,6 @@ SetSignerList::replaceSignerList()
|
||||
|
||||
// If we succeeded, the new entry counts against the
|
||||
// creator's reserve.
|
||||
auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx);
|
||||
adjustOwnerCount(view(), sle, sponsor, addedOwnerCount, viewJ);
|
||||
addSponsorToLedgerEntry(signerList, sponsor);
|
||||
return tesSUCCESS;
|
||||
|
||||
@@ -402,9 +402,7 @@ SetTrust::doApply()
|
||||
// well. A person with no intention of using the gateway
|
||||
// could use the extra XRP for their own purposes.
|
||||
|
||||
XRPAmount const reserveCreate(
|
||||
(uOwnerCount < 2) ? XRPAmount(beast::zero)
|
||||
: view().fees().accountReserve(uOwnerCount + 1));
|
||||
bool const freeTrustLine = uOwnerCount < 2;
|
||||
|
||||
std::uint32_t uQualityIn(bQualityIn ? ctx_.tx.getFieldU32(sfQualityIn) : 0);
|
||||
std::uint32_t uQualityOut(
|
||||
@@ -455,6 +453,8 @@ SetTrust::doApply()
|
||||
SLE::pointer sleRippleState =
|
||||
view().peek(keylet::line(account_, uDstAccountID, currency));
|
||||
|
||||
auto const sponsor = getTxReserveSponsor(view(), ctx_.tx);
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
STAmount saLowBalance;
|
||||
@@ -678,7 +678,9 @@ SetTrust::doApply()
|
||||
view(), sleRippleState, uLowAccountID, uHighAccountID, viewJ);
|
||||
}
|
||||
// Reserve is not scaled by load.
|
||||
else if (bReserveIncrease && mPriorBalance < reserveCreate)
|
||||
else if (auto const ret = checkInsufficientReserve(
|
||||
view(), sle, mPriorBalance, sponsor, 0);
|
||||
!freeTrustLine && bReserveIncrease && !isTesSuccess(ret))
|
||||
{
|
||||
JLOG(j_.trace()) << "Delay transaction: Insufficent reserve to "
|
||||
"add trust line.";
|
||||
@@ -707,8 +709,14 @@ SetTrust::doApply()
|
||||
<< "Redundant: Setting non-existent ripple line to defaults.";
|
||||
return tecNO_LINE_REDUNDANT;
|
||||
}
|
||||
else if (mPriorBalance < reserveCreate) // Reserve is not scaled by
|
||||
// load.
|
||||
else if (auto const ret = checkInsufficientReserve(
|
||||
ctx_.view(),
|
||||
sle,
|
||||
mPriorBalance,
|
||||
sponsor,
|
||||
1);
|
||||
!freeTrustLine &&
|
||||
!isTesSuccess(ret)) // Reserve is not scaled by load.
|
||||
{
|
||||
JLOG(j_.trace()) << "Delay transaction: Line does not exist. "
|
||||
"Insufficent reserve to create line.";
|
||||
|
||||
@@ -177,9 +177,10 @@ VaultCreate::doApply()
|
||||
auto const sponsor = getTxReserveSponsor(view(), tx);
|
||||
adjustOwnerCount(view(), owner, sponsor, 1, j_);
|
||||
addSponsorToLedgerEntry(vault, sponsor);
|
||||
auto ownerCount = owner->at(sfOwnerCount);
|
||||
if (mPriorBalance < view().fees().accountReserve(ownerCount))
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(view(), owner, mPriorBalance, sponsor, 0);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto maybePseudo = createPseudoAccount(view(), vault->key(), sfVaultID);
|
||||
if (!maybePseudo)
|
||||
|
||||
@@ -1066,11 +1066,11 @@ applyCreateAccountAttestations(
|
||||
|
||||
// Check reserve
|
||||
auto const balance = (*sleDoor)[sfBalance];
|
||||
auto const reserve =
|
||||
psb.fees().accountReserve((*sleDoor)[sfOwnerCount] + 1);
|
||||
|
||||
if (balance < reserve)
|
||||
return Unexpected(tecINSUFFICIENT_RESERVE);
|
||||
auto const sponsor = std::optional<std::shared_ptr<SLE const>>();
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(psb, sleDoor, balance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return Unexpected(ret); // tecINSUFFICIENT_RESERVE
|
||||
}
|
||||
|
||||
std::vector<Attestations::AttestationCreateAccount> atts;
|
||||
@@ -1507,11 +1507,11 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
auto const balance = (*sleAcc)[sfBalance];
|
||||
auto const reserve =
|
||||
ctx.view.fees().accountReserve((*sleAcc)[sfOwnerCount] + 1);
|
||||
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(ctx.view, ctx.tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(ctx.view, sleAcc, balance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -2074,11 +2074,11 @@ XChainCreateClaimID::preclaim(PreclaimContext const& ctx)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
auto const balance = (*sleAcc)[sfBalance];
|
||||
auto const reserve =
|
||||
ctx.view.fees().accountReserve((*sleAcc)[sfOwnerCount] + 1);
|
||||
|
||||
if (balance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
auto const sponsor = getTxReserveSponsor(ctx.view, ctx.tx);
|
||||
if (auto const ret =
|
||||
checkInsufficientReserve(ctx.view, sleAcc, balance, sponsor, 1);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
|
||||
@@ -452,11 +452,22 @@ areCompatible(
|
||||
beast::Journal::Stream& s,
|
||||
char const* reason);
|
||||
|
||||
TER
|
||||
checkInsufficientReserve(
|
||||
ReadView const& view,
|
||||
std::shared_ptr<SLE const> accSle,
|
||||
STAmount const& accBalance,
|
||||
std::optional<std::shared_ptr<SLE const>> const& _sponsorSle,
|
||||
std::int32_t ownerCountDelta);
|
||||
|
||||
std::optional<std::shared_ptr<SLE>>
|
||||
getTxReserveSponsor(ApplyView& view, STTx const& tx);
|
||||
|
||||
std::optional<std::shared_ptr<SLE const>>
|
||||
getTxReserveSponsor(ReadView const& view, STTx const& tx);
|
||||
|
||||
std::optional<std::shared_ptr<SLE>>
|
||||
getLedgerEntryReserveSponsor(ApplyView& view, SLE::ref sle);
|
||||
getLedgerEntryReserveSponsor(ApplyView& view, std::shared_ptr<SLE> sle);
|
||||
|
||||
void
|
||||
addSponsorToLedgerEntry(
|
||||
|
||||
@@ -1021,6 +1021,43 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TER
|
||||
checkInsufficientReserve(
|
||||
ReadView const& view,
|
||||
std::shared_ptr<SLE const> accSle,
|
||||
STAmount const& accBalance,
|
||||
std::optional<std::shared_ptr<SLE const>> const& _sponsorSle,
|
||||
std::int32_t ownerCountDelta)
|
||||
{
|
||||
if (_sponsorSle.has_value())
|
||||
{
|
||||
auto const sponsorSle = _sponsorSle.value();
|
||||
auto const sponsorBalance = sponsorSle->getFieldAmount(sfBalance);
|
||||
STAmount const sponsorReserve{view.fees().accountReserve(
|
||||
sponsorSle->getFieldU32(sfOwnerCount),
|
||||
sponsorSle->getFieldU32(sfSponsoredOwnerCount),
|
||||
sponsorSle->getFieldU32(sfSponsoringOwnerCount) + ownerCountDelta,
|
||||
sponsorSle->isFieldPresent(sfSponsor),
|
||||
sponsorSle->getFieldU32(sfSponsoringAccountCount))};
|
||||
|
||||
if (sponsorBalance < sponsorReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
STAmount const reserve{view.fees().accountReserve(
|
||||
accSle->getFieldU32(sfOwnerCount) + ownerCountDelta,
|
||||
accSle->getFieldU32(sfSponsoredOwnerCount),
|
||||
accSle->getFieldU32(sfSponsoringOwnerCount),
|
||||
accSle->isFieldPresent(sfSponsor),
|
||||
accSle->getFieldU32(sfSponsoringAccountCount))};
|
||||
|
||||
if (accBalance < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<SLE>>
|
||||
getTxReserveSponsor(ApplyView& view, STTx const& tx)
|
||||
{
|
||||
@@ -1037,8 +1074,24 @@ getTxReserveSponsor(ApplyView& view, STTx const& tx)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<SLE const>>
|
||||
getTxReserveSponsor(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
if (tx.isFieldPresent(sfSponsor))
|
||||
{
|
||||
auto const sponsorObj = tx.getFieldObject(sfSponsor);
|
||||
auto const flags = sponsorObj.getFlags();
|
||||
auto const sponsorID = sponsorObj.getAccountID(sfAccount);
|
||||
if (flags & tfSponsorReserve)
|
||||
{
|
||||
return view.read(keylet::account(sponsorID));
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<SLE>>
|
||||
getLedgerEntryReserveSponsor(ApplyView& view, SLE::ref sle)
|
||||
getLedgerEntryReserveSponsor(ApplyView& view, std::shared_ptr<SLE> sle)
|
||||
{
|
||||
if (sle->isFieldPresent(sfSponsorAccount))
|
||||
return view.peek(keylet::account(sle->getAccountID(sfSponsorAccount)));
|
||||
|
||||
Reference in New Issue
Block a user