1#include <xrpl/tx/transactors/sponsor/SponsorshipTransfer.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/core/ServiceRegistry.h>
7#include <xrpl/ledger/ApplyView.h>
8#include <xrpl/ledger/ReadView.h>
9#include <xrpl/ledger/helpers/AccountRootHelpers.h>
10#include <xrpl/ledger/helpers/SponsorHelpers.h>
11#include <xrpl/protocol/Indexes.h>
12#include <xrpl/protocol/SField.h>
13#include <xrpl/protocol/TER.h>
14#include <xrpl/protocol/TxFlags.h>
15#include <xrpl/protocol/XRPAmount.h>
16#include <xrpl/tx/Transactor.h>
33 auto const currentValue = sle->getFieldU32(field);
37 UNREACHABLE(
"xrpl::incrementSponsorCount : sponsor field overflow");
42 sle->at(field) = currentValue + delta;
55 auto const currentValue = sle->getFieldU32(field);
56 if (currentValue < delta)
59 UNREACHABLE(
"xrpl::decrementSponsorCount : sponsor field underflow");
64 sle->at(field) = currentValue - delta;
77 auto const currentReserveCount = sponsorshipSle->getFieldU32(sfRemainingOwnerCount);
78 if (currentReserveCount < delta)
82 UNREACHABLE(
"xrpl::decrementPrefundedReserveCount : invalid reserve count");
87 sponsorshipSle->at(sfRemainingOwnerCount) = currentReserveCount - delta;
88 view.
update(sponsorshipSle);
95 return tfSponsorshipTransferMask;
101 static constexpr auto transferFlags =
102 tfSponsorshipCreate | tfSponsorshipReassign | tfSponsorshipEnd;
105 JLOG(ctx.
j.
debug()) <<
"preflight: Only one SponsorshipTransfer flag can be set per tx.";
109 if (ctx.
tx.
isFlag(tfSponsorshipCreate))
115 JLOG(ctx.
j.
debug()) <<
"preflight: sfSponsor must be present when creating sponsorship";
122 <<
"preflight: spfSponsorReserve must be set when creating sponsorship";
129 <<
"preflight: sfSponsee must not be present when creating sponsorship";
134 if (ctx.
tx.
isFlag(tfSponsorshipReassign))
142 <<
"preflight: sfSponsor must be present when reassigning sponsorship";
149 <<
"preflight: spfSponsorReserve must be set when reassigning sponsorship";
155 <<
"preflight: sfSponsee must not be present when reassigning sponsorship";
160 if (ctx.
tx.
isFlag(tfSponsorshipEnd))
167 <<
"preflight: sfSponsor must not be present when ending sponsorship";
179 "xrpl::SponsorshipTransfer::preflight : sfSponsorFlags present without sfSponsor "
180 "when ending sponsorship");
188 JLOG(ctx.
j.
debug()) <<
"preflight: sfSponsee should not be the same as the account";
196 bool const isCreateOrReassign =
199 bool const isAccountReserveSponsorship =
202 if (isAccountReserveSponsorship && !ctx.
tx.
isFieldPresent(sfSponsorSignature))
204 JLOG(ctx.
j.
debug()) <<
"preflight: account sponsorship requires sfSponsorSignature";
214 auto const objectID = ctx.
tx[~sfObjectID];
216 if (!newSponsorSleExpected)
217 return newSponsorSleExpected.error();
218 auto const newSponsorSle = *newSponsorSleExpected;
220 auto const account = ctx.
tx[sfAccount];
221 auto const sponseeID = ctx.
tx[~sfSponsee].value_or(account);
239 auto const* sponsorField = &sfSponsor;
241 if (objectID.has_value())
256 targetSle = objectSle;
260 bool const isSponsored = targetSle->isFieldPresent(*sponsorField);
262 if (ctx.
tx.
isFlag(tfSponsorshipCreate))
266 if (!newSponsorSle || isSponsored)
269 else if (ctx.
tx.
isFlag(tfSponsorshipReassign))
273 if (!newSponsorSle || !isSponsored)
279 if (targetSle->getAccountID(*sponsorField) == ctx.
tx.
getAccountID(sfSponsor))
282 else if (ctx.
tx.
isFlag(tfSponsorshipEnd))
285 if (newSponsorSle || !isSponsored)
289 auto const sponsor = targetSle->getAccountID(*sponsorField);
290 if (account != sponsor && account != sponseeID)
300 auto const objectID =
ctx_.tx[~sfObjectID];
308 if (sle->getAccountID(sfAccount) ==
accountID_)
310 return sle->getFieldAmount(sfBalance).xrp();
313 bool const isCreate =
ctx_.tx.isFlag(tfSponsorshipCreate);
314 bool const isReassign =
ctx_.tx.isFlag(tfSponsorshipReassign);
316 if (objectID.has_value())
331 auto const ownerCountDelta =
335 if (isCreate || isReassign)
337 auto const newSponsor =
ctx_.tx[~sfSponsor];
339 newSponsor.has_value(),
340 "xrpl::SponsorshipTransfer::doApply : sfSponsor present for object sponsor "
344 auto const newSponsorID = *newSponsor;
352 ctx_.getApplyViewContext(),
354 sponseeSle->getFieldAmount(sfBalance).xrp(),
356 {.ownerCountDelta = ownerCountDelta},
365 view(), ownerSle, sfSponsoredOwnerCount, ownerCountDelta);
371 auto const oldSponsorID = objectSle->getAccountID(sponsorField);
380 view(), oldSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
387 view(), newSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
392 objectSle->setAccountID(sponsorField, newSponsorID);
405 else if (
ctx_.tx.isFlag(tfSponsorshipEnd))
408 auto const oldSponsorID = objectSle->getAccountID(sponsorField);
421 view(), sponseeSle, sfSponsoredOwnerCount, ownerCountDelta);
427 view(), oldSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
432 objectSle->makeFieldAbsent(sponsorField);
440 if (isCreate || isReassign)
442 auto const newSponsor =
ctx_.tx[~sfSponsor];
444 newSponsor.has_value(),
445 "xrpl::SponsorshipTransfer::doApply : sfSponsor present for account sponsor "
449 auto const newSponsorID = *newSponsor;
455 ctx_.getApplyViewContext(),
457 sponseeSle->getFieldAmount(sfBalance).xrp(),
459 {.accountCountDelta = 1},
466 auto const oldSponsorID = sponseeSle->getAccountID(sfSponsor);
487 sponseeSle->setAccountID(sfSponsor, newSponsorID);
490 else if (
ctx_.tx.isFlag(tfSponsorshipEnd))
493 auto const oldSponsorID = sponseeSle->getAccountID(sfSponsor);
503 ctx_.getApplyViewContext(),
505 balanceBeforeFee(sponseeSle),
507 {.accountCountDelta = 1},
512 sponseeSle->makeFieldAbsent(sfSponsor);
A generic endpoint for log messages.
Writeable view to a ledger, for applying a transaction.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry > pointer
std::shared_ptr< STLedgerEntry const > const & const_ref
std::shared_ptr< STLedgerEntry const > const_pointer
bool isFlag(std::uint32_t) const
bool isFieldPresent(SField const &field) const
AccountID getAccountID(SField const &field) const
std::uint32_t getFlags() const
AccountID const accountID_
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet sponsorship(AccountID const &sponsor, AccountID const &sponsee) noexcept
A Sponsorship.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static TER decrementSponsorCount(ApplyView &view, SLE::ref sle, SF_UINT32 const &field, std::uint32_t const delta)
TypedField< STInteger< std::uint32_t > > SF_UINT32
bool isReserveSponsored(STTx const &tx)
Whether the transaction's reserve is sponsored (sfSponsor present + spfSponsorReserve set).
std::expected< SLE::pointer, TER > getTxReserveSponsor(ApplyViewContext ctx)
Return a mutable SLE for the transaction's reserve sponsor account.
TERSubset< CanCvtToNotTEC > NotTEC
std::uint32_t getLedgerEntryOwnerCount(SLE const &sle)
Return the number of owner-count units the ledger entry consumes.
TER checkReserve(ApplyViewContext ctx, SLE::const_ref accSle, XRPAmount accBalance, SLE::const_ref sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
static TER decrementPrefundedReserveCount(ApplyView &view, SLE::ref sponsorshipSle, std::uint32_t const delta)
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
std::optional< AccountID > getTxReserveSponsorID(STTx const &tx)
Return the AccountID of the transaction's reserve sponsor, or nullopt if unsponsored.
bool isLedgerEntryOwner(ReadView const &view, SLE const &sle, AccountID const &account)
Whether account is the owner of a ledger entry for sponsorship purposes.
static TER incrementSponsorCount(ApplyView &view, SLE::ref sle, SF_UINT32 const &field, std::uint32_t const delta)
SF_ACCOUNT const & getLedgerEntrySponsorField(SLE const &sle, AccountID const &owner)
Return the SField used to store the reserve sponsor for owner on sle.
bool isLedgerEntrySupportedBySponsorship(SLE const &sle)
Whether this ledger entry type can have a reserve sponsor attached to it.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.