mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 09:16:47 +00:00
Add SponsorTransfer
This commit is contained in:
@@ -525,6 +525,11 @@ TRANSACTION(ttBATCH, 71, Batch, Delegation::notDelegatable, ({
|
||||
{sfBatchSigners, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction transfer sponsor */
|
||||
TRANSACTION(ttSPONSOR_TRANSFER, 72, SponsorTransfer, Delegation::notDelegatable, ({
|
||||
{sfLedgerIndex, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the status of the various amendments.
|
||||
|
||||
For details, see: https://xrpl.org/amendments.html
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/check.h>
|
||||
#include <test/jtx/did.h>
|
||||
#include <test/jtx/owners.h>
|
||||
#include <test/jtx/sponsor.h>
|
||||
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -46,6 +47,141 @@ public:
|
||||
sponsor::as(sponsor),
|
||||
sponsor::sig(sponsor),
|
||||
ter(temDISABLED));
|
||||
|
||||
env(sponsor::transfer(alice), ter(temDISABLED));
|
||||
}
|
||||
|
||||
void
|
||||
testTransferSponsor()
|
||||
{
|
||||
testcase("Transfer Sponsor");
|
||||
using namespace test::jtx;
|
||||
|
||||
{
|
||||
// sponsor account
|
||||
Env env{*this, testable_amendments()};
|
||||
Account const alice("alice");
|
||||
Account const sponsor1("sponsor1");
|
||||
Account const sponsor2("sponsor2");
|
||||
env.fund(XRP(10000), alice, sponsor1, sponsor2);
|
||||
|
||||
env(sponsor::transfer(alice),
|
||||
sponsor::as(sponsor1, tfSponsorReserve),
|
||||
sponsor::sig(sponsor1));
|
||||
env.close();
|
||||
|
||||
env.require(sponsored_owners(alice, 0));
|
||||
env.require(sponsored_owners(sponsor1, 0));
|
||||
env.require(sponsoring_owners(alice, 0));
|
||||
env.require(sponsoring_owners(sponsor1, 0));
|
||||
env.require(sponsoring_account_count(alice, 0));
|
||||
env.require(sponsoring_account_count(sponsor1, 1));
|
||||
auto const sle1 = env.le(keylet::account(alice));
|
||||
BEAST_EXPECT(sle1->isFieldPresent(sfSponsorAccount));
|
||||
BEAST_EXPECT(sle1->getAccountID(sfSponsorAccount) == sponsor1.id());
|
||||
|
||||
// transfer sponsor
|
||||
env(sponsor::transfer(alice),
|
||||
sponsor::as(sponsor2, tfSponsorReserve),
|
||||
sponsor::sig(sponsor2));
|
||||
env.close();
|
||||
|
||||
env.require(sponsored_owners(alice, 0));
|
||||
env.require(sponsored_owners(sponsor1, 0));
|
||||
env.require(sponsored_owners(sponsor2, 0));
|
||||
env.require(sponsoring_owners(alice, 0));
|
||||
env.require(sponsoring_owners(sponsor1, 0));
|
||||
env.require(sponsoring_owners(sponsor2, 0));
|
||||
env.require(sponsoring_account_count(alice, 0));
|
||||
env.require(sponsoring_account_count(sponsor1, 0));
|
||||
env.require(sponsoring_account_count(sponsor2, 1));
|
||||
auto const sle2 = env.le(keylet::account(alice));
|
||||
BEAST_EXPECT(sle2->isFieldPresent(sfSponsorAccount));
|
||||
BEAST_EXPECT(sle2->getAccountID(sfSponsorAccount) == sponsor2.id());
|
||||
|
||||
// dissolve sponsor
|
||||
env(sponsor::transfer(alice));
|
||||
env.close();
|
||||
|
||||
env.require(sponsored_owners(alice, 0));
|
||||
env.require(sponsored_owners(sponsor1, 0));
|
||||
env.require(sponsored_owners(sponsor2, 0));
|
||||
env.require(sponsoring_owners(alice, 0));
|
||||
env.require(sponsoring_owners(sponsor1, 0));
|
||||
env.require(sponsoring_owners(sponsor2, 0));
|
||||
env.require(sponsoring_account_count(alice, 0));
|
||||
env.require(sponsoring_account_count(sponsor1, 0));
|
||||
env.require(sponsoring_account_count(sponsor2, 0));
|
||||
auto const sle3 = env.le(keylet::account(alice));
|
||||
BEAST_EXPECT(!sle3->isFieldPresent(sfSponsorAccount));
|
||||
}
|
||||
{
|
||||
// sponsor object
|
||||
Env env{*this, testable_amendments()};
|
||||
Account const alice("alice");
|
||||
Account const bob("bob");
|
||||
Account const sponsor1("sponsor1");
|
||||
Account const sponsor2("sponsor2");
|
||||
env.fund(XRP(10000), alice, bob, sponsor1, sponsor2);
|
||||
|
||||
auto const seq = env.seq(alice);
|
||||
env(check::create(alice, bob, XRP(1)));
|
||||
env.close();
|
||||
|
||||
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));
|
||||
env.close();
|
||||
|
||||
env.require(owners(alice, 1));
|
||||
env.require(sponsored_owners(alice, 1));
|
||||
env.require(sponsored_owners(sponsor1, 0));
|
||||
env.require(sponsoring_owners(alice, 0));
|
||||
env.require(sponsoring_owners(sponsor1, 1));
|
||||
env.require(sponsoring_account_count(alice, 0));
|
||||
env.require(sponsoring_account_count(sponsor1, 0));
|
||||
auto const sle1 = env.le(keylet::unchecked(checkId));
|
||||
BEAST_EXPECT(sle1->isFieldPresent(sfSponsorAccount));
|
||||
BEAST_EXPECT(sle1->getAccountID(sfSponsorAccount) == sponsor1.id());
|
||||
|
||||
// transfer sponsor
|
||||
env(sponsor::transfer(alice, checkId),
|
||||
sponsor::as(sponsor2, tfSponsorReserve),
|
||||
sponsor::sig(sponsor2));
|
||||
env.close();
|
||||
|
||||
env.require(sponsored_owners(alice, 1));
|
||||
env.require(sponsored_owners(sponsor1, 0));
|
||||
env.require(sponsored_owners(sponsor2, 0));
|
||||
env.require(sponsoring_owners(alice, 0));
|
||||
env.require(sponsoring_owners(sponsor1, 0));
|
||||
env.require(sponsoring_owners(sponsor2, 1));
|
||||
env.require(sponsoring_account_count(alice, 0));
|
||||
env.require(sponsoring_account_count(sponsor1, 0));
|
||||
env.require(sponsoring_account_count(sponsor2, 0));
|
||||
auto const sle2 = env.le(keylet::unchecked(checkId));
|
||||
BEAST_EXPECT(sle2->isFieldPresent(sfSponsorAccount));
|
||||
BEAST_EXPECT(sle2->getAccountID(sfSponsorAccount) == sponsor2.id());
|
||||
|
||||
// dissolve sponsor
|
||||
env(sponsor::transfer(alice, checkId));
|
||||
env.close();
|
||||
|
||||
env.require(sponsored_owners(alice, 0));
|
||||
env.require(sponsored_owners(sponsor1, 0));
|
||||
env.require(sponsored_owners(sponsor2, 0));
|
||||
env.require(sponsoring_owners(alice, 0));
|
||||
env.require(sponsoring_owners(sponsor1, 0));
|
||||
env.require(sponsoring_owners(sponsor2, 0));
|
||||
env.require(sponsoring_account_count(alice, 0));
|
||||
env.require(sponsoring_account_count(sponsor1, 0));
|
||||
env.require(sponsoring_account_count(sponsor2, 0));
|
||||
auto const sle3 = env.le(keylet::unchecked(checkId));
|
||||
BEAST_EXPECT(!sle3->isFieldPresent(sfSponsorAccount));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -455,6 +591,7 @@ public:
|
||||
run() override
|
||||
{
|
||||
testDisabled();
|
||||
testTransferSponsor();
|
||||
testSponsorFee();
|
||||
testSponsorAccount();
|
||||
testSponsorReserve();
|
||||
|
||||
@@ -30,21 +30,13 @@ namespace jtx {
|
||||
namespace sponsor {
|
||||
|
||||
Json::Value
|
||||
transferAccount(jtx::Account const& account)
|
||||
transfer(jtx::Account const& account, std::optional<uint256> const& index)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = "SponsorTransfer";
|
||||
jv[sfSponsor.jsonName] = account.human();
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
transferObject(uint256 const& id)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = "SponsorTransfer";
|
||||
jv[sfLedgerIndex.jsonName] = to_string(id);
|
||||
jv[jss::TransactionType] = jss::SponsorTransfer;
|
||||
jv[jss::Account] = account.human();
|
||||
if (index)
|
||||
jv[sfLedgerIndex.jsonName] = to_string(*index);
|
||||
return jv;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,10 @@ namespace jtx {
|
||||
|
||||
namespace sponsor {
|
||||
|
||||
// Json::Value
|
||||
// transferAccount(jtx::Account const& account);
|
||||
|
||||
// Json::Value
|
||||
// transferObject(uint256 const& id);
|
||||
Json::Value
|
||||
transfer(
|
||||
jtx::Account const& account,
|
||||
std::optional<uint256> const& index = std::nullopt);
|
||||
|
||||
struct as
|
||||
{
|
||||
|
||||
285
src/xrpld/app/tx/detail/SponsorTransfer.cpp
Normal file
285
src/xrpld/app/tx/detail/SponsorTransfer.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/app/tx/detail/SponsorTransfer.h>
|
||||
#include <xrpld/ledger/ReadView.h>
|
||||
#include <xrpld/ledger/View.h>
|
||||
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
NotTEC
|
||||
SponsorTransfer::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (!ctx.rules.enabled(featureSponsor))
|
||||
return temDISABLED;
|
||||
|
||||
if (auto const ter = preflight1(ctx))
|
||||
return ter;
|
||||
|
||||
if (ctx.tx.getFlags() & tfUniversalMask)
|
||||
return temINVALID_FLAG;
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::optional<AccountID>
|
||||
getLedgerEntryOwner(
|
||||
ReadView const& view,
|
||||
T const& sle,
|
||||
AccountID const& account)
|
||||
{
|
||||
switch (sle->getType())
|
||||
{
|
||||
case ltNFTOKEN_OFFER:
|
||||
case ltORACLE:
|
||||
case ltPERMISSIONED_DOMAIN:
|
||||
case ltVAULT:
|
||||
return sle->getAccountID(sfOwner);
|
||||
case ltCHECK:
|
||||
case ltDID:
|
||||
case ltTICKET:
|
||||
case ltOFFER:
|
||||
case ltXCHAIN_OWNED_CLAIM_ID:
|
||||
case ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID:
|
||||
case ltESCROW:
|
||||
case ltPAYCHAN:
|
||||
case ltMPTOKEN:
|
||||
case ltDELEGATE:
|
||||
case ltBRIDGE:
|
||||
case ltDEPOSIT_PREAUTH:
|
||||
return sle->getAccountID(sfAccount);
|
||||
case ltMPTOKEN_ISSUANCE:
|
||||
return sle->getAccountID(sfIssuer);
|
||||
case ltSIGNER_LIST: {
|
||||
auto const signerList = view.read(keylet::signers(account));
|
||||
if (!signerList)
|
||||
return std::nullopt;
|
||||
if (signerList->getFieldH256(sfLedgerIndex) ==
|
||||
sle->getFieldH256(sfLedgerIndex))
|
||||
return account;
|
||||
return std::nullopt;
|
||||
}
|
||||
case ltCREDENTIAL: {
|
||||
if (sle->getFlags() & lsfAccepted)
|
||||
return sle->getAccountID(sfSubject);
|
||||
return sle->getAccountID(sfIssuer);
|
||||
}
|
||||
// case ltNFTOKEN_PAGE:
|
||||
// case ltRIPPLE_STATE:
|
||||
case ltACCOUNT_ROOT: {
|
||||
// AccountRoot is not supported for object sponsorship
|
||||
return std::nullopt;
|
||||
}
|
||||
case ltNEGATIVE_UNL:
|
||||
case ltDIR_NODE:
|
||||
case ltAMENDMENTS:
|
||||
case ltLEDGER_HASHES:
|
||||
case ltFEE_SETTINGS:
|
||||
case ltAMM:
|
||||
return std::nullopt;
|
||||
default:
|
||||
return std::nullopt;
|
||||
};
|
||||
}
|
||||
|
||||
TER
|
||||
SponsorTransfer::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
auto const index = ctx.tx[~sfLedgerIndex];
|
||||
|
||||
if (index)
|
||||
{
|
||||
auto const sle = ctx.view.read(keylet::unchecked(*index));
|
||||
if (!sle)
|
||||
return tecNO_ENTRY;
|
||||
|
||||
auto const owner =
|
||||
getLedgerEntryOwner(ctx.view, sle, ctx.tx[sfAccount]);
|
||||
if (!owner)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
if (sle->isFieldPresent(sfSponsorAccount))
|
||||
{
|
||||
auto const sponsor = sle->getAccountID(sfSponsorAccount);
|
||||
if (sponsor == owner)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// TODO: check reserve
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check reserve
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const accSle = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
|
||||
if (!accSle)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (accSle->isFieldPresent(sfSponsorAccount))
|
||||
{
|
||||
// TODO: check reserve
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check reserve
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
SponsorTransfer::doApply()
|
||||
{
|
||||
auto const& tx = ctx_.tx;
|
||||
|
||||
auto const index = tx[~sfLedgerIndex];
|
||||
|
||||
auto const accSle = view().peek(keylet::account(account_));
|
||||
if (!accSle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (index)
|
||||
{
|
||||
// transfer object sponsor
|
||||
auto const objSle = view().peek(keylet::unchecked(*index));
|
||||
if (!objSle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const owner = getLedgerEntryOwner(view(), objSle, account_);
|
||||
if (!owner)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ownerSle = view().peek(keylet::account(*owner));
|
||||
if (!ownerSle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (tx.isFieldPresent(sfSponsor))
|
||||
{
|
||||
auto const sponsorObj = tx.getFieldObject(sfSponsor);
|
||||
auto const oldSponsor = objSle->getAccountID(sfSponsorAccount);
|
||||
auto const newSponsor = sponsorObj[sfAccount];
|
||||
// decrement old sponsoring count if exists
|
||||
if (auto const oldSponsorSle =
|
||||
view().peek(keylet::account(oldSponsor)))
|
||||
{
|
||||
oldSponsorSle->setFieldU32(
|
||||
sfSponsoringOwnerCount,
|
||||
oldSponsorSle->getFieldU32(sfSponsoringOwnerCount) - 1);
|
||||
view().update(oldSponsorSle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update owner's sponsored count
|
||||
ownerSle->setFieldU32(
|
||||
sfSponsoredOwnerCount,
|
||||
ownerSle->getFieldU32(sfSponsoredOwnerCount) + 1);
|
||||
view().update(ownerSle);
|
||||
}
|
||||
// increment new sponsoring count
|
||||
auto const newSponsorSle = view().peek(keylet::account(newSponsor));
|
||||
newSponsorSle->setFieldU32(
|
||||
sfSponsoringOwnerCount,
|
||||
newSponsorSle->getFieldU32(sfSponsoringOwnerCount) + 1);
|
||||
view().update(newSponsorSle);
|
||||
|
||||
objSle->setAccountID(sfSponsorAccount, newSponsor);
|
||||
view().update(objSle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// dissolve object sponsor
|
||||
auto const oldSponsor = objSle->getAccountID(sfSponsorAccount);
|
||||
// decrement sponsored count
|
||||
accSle->setFieldU32(
|
||||
sfSponsoredOwnerCount,
|
||||
accSle->getFieldU32(sfSponsoredOwnerCount) - 1);
|
||||
view().update(accSle);
|
||||
// decrement old sponsoring count
|
||||
if (auto const oldSponsorSle =
|
||||
view().peek(keylet::account(oldSponsor)))
|
||||
{
|
||||
oldSponsorSle->setFieldU32(
|
||||
sfSponsoringOwnerCount,
|
||||
oldSponsorSle->getFieldU32(sfSponsoringOwnerCount) - 1);
|
||||
view().update(oldSponsorSle);
|
||||
}
|
||||
|
||||
// remove sponsor from object
|
||||
objSle->makeFieldAbsent(sfSponsorAccount);
|
||||
view().update(objSle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transfer Account sponsor
|
||||
if (tx.isFieldPresent(sfSponsor))
|
||||
{
|
||||
// transfer account sponsor
|
||||
auto const sponsorObj = tx.getFieldObject(sfSponsor);
|
||||
// increment new sponsoring count
|
||||
auto const newSponsor = sponsorObj[sfAccount];
|
||||
auto const newSponsorSle = view().peek(keylet::account(newSponsor));
|
||||
newSponsorSle->setFieldU32(
|
||||
sfSponsoringAccountCount,
|
||||
newSponsorSle->getFieldU32(sfSponsoringAccountCount) + 1);
|
||||
view().update(newSponsorSle);
|
||||
// decrement old sponsoring count
|
||||
if (accSle->isFieldPresent(sfSponsorAccount))
|
||||
{
|
||||
auto const oldSponsor = accSle->getAccountID(sfSponsorAccount);
|
||||
auto const oldSponsorSle =
|
||||
view().peek(keylet::account(oldSponsor));
|
||||
oldSponsorSle->setFieldU32(
|
||||
sfSponsoringAccountCount,
|
||||
oldSponsorSle->getFieldU32(sfSponsoringAccountCount) - 1);
|
||||
view().update(oldSponsorSle);
|
||||
}
|
||||
accSle->setAccountID(sfSponsorAccount, newSponsor);
|
||||
view().update(accSle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// dissolve account sponsor
|
||||
auto const oldSponsor = accSle->getAccountID(sfSponsorAccount);
|
||||
accSle->makeFieldAbsent(sfSponsorAccount);
|
||||
// decrement account sponsoring count
|
||||
auto const oldSponsorSle = view().peek(keylet::account(oldSponsor));
|
||||
oldSponsorSle->setFieldU32(
|
||||
sfSponsoringAccountCount,
|
||||
oldSponsorSle->getFieldU32(sfSponsoringAccountCount) - 1);
|
||||
view().update(oldSponsorSle);
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
48
src/xrpld/app/tx/detail/SponsorTransfer.h
Normal file
48
src/xrpld/app/tx/detail/SponsorTransfer.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_SPONSORTRANSFER_H_INCLUDED
|
||||
#define RIPPLE_TX_SPONSORTRANSFER_H_INCLUDED
|
||||
|
||||
#include <xrpld/app/tx/detail/Transactor.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class SponsorTransfer : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit SponsorTransfer(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <xrpld/app/tx/detail/SetRegularKey.h>
|
||||
#include <xrpld/app/tx/detail/SetSignerList.h>
|
||||
#include <xrpld/app/tx/detail/SetTrust.h>
|
||||
#include <xrpld/app/tx/detail/SponsorTransfer.h>
|
||||
#include <xrpld/app/tx/detail/VaultClawback.h>
|
||||
#include <xrpld/app/tx/detail/VaultCreate.h>
|
||||
#include <xrpld/app/tx/detail/VaultDelete.h>
|
||||
|
||||
Reference in New Issue
Block a user