mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-11 09:10:21 +00:00
Compare commits
4 Commits
ripple/was
...
mvadari/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba6789292d | ||
|
|
fd2cc6dcb3 | ||
|
|
c7adb215ed | ||
|
|
71ee0f400b |
@@ -279,6 +279,8 @@ words:
|
||||
- sles
|
||||
- soci
|
||||
- socidb
|
||||
- sponsee
|
||||
- sponsees
|
||||
- SRPMS
|
||||
- sslws
|
||||
- statsd
|
||||
@@ -292,7 +294,6 @@ words:
|
||||
- sttx
|
||||
- stvar
|
||||
- stvector
|
||||
- stxchainattestations
|
||||
- summands
|
||||
- superpeer
|
||||
- superpeers
|
||||
@@ -327,6 +328,7 @@ words:
|
||||
- unserviced
|
||||
- unshareable
|
||||
- unshares
|
||||
- unsponsored
|
||||
- unsquelch
|
||||
- unsquelched
|
||||
- unsquelching
|
||||
@@ -345,8 +347,6 @@ words:
|
||||
- writeme
|
||||
- wsrch
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xrpkuwait
|
||||
|
||||
15
docs/build/environment.md
vendored
15
docs/build/environment.md
vendored
@@ -33,9 +33,10 @@ with a single command and without installing anything system-wide:
|
||||
nix --experimental-features 'nix-command flakes' develop
|
||||
```
|
||||
|
||||
On **Linux**, Nix also provides the compiler (GCC). On **macOS**, the shell uses
|
||||
your **system-wide Apple Clang** as the compiler, so you still need to manage
|
||||
its version (see below).
|
||||
On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides
|
||||
Clang. If you instead opt to use your system-wide Apple Clang (via
|
||||
`nix develop .#apple-clang`), you need to manage its version yourself (see
|
||||
below).
|
||||
|
||||
See [Using the Nix development shell](./nix.md) for installation and usage
|
||||
details, including how to select a different compiler.
|
||||
@@ -48,10 +49,10 @@ details, including how to select a different compiler.
|
||||
|
||||
### macOS: managing the Apple Clang version
|
||||
|
||||
Because the Nix shell uses the system-wide Apple Clang on macOS, the compiler
|
||||
version is whatever your installed Xcode (or Command Line Tools) provides. The
|
||||
following command should return a version greater than or equal to the
|
||||
[minimum required](#tested-compiler-versions):
|
||||
If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`),
|
||||
the compiler version is whatever your installed Xcode (or Command Line Tools)
|
||||
provides. The following command should return a version greater than or equal to
|
||||
the [minimum required](#tested-compiler-versions):
|
||||
|
||||
```bash
|
||||
clang --version
|
||||
|
||||
40
docs/build/nix.md
vendored
40
docs/build/nix.md
vendored
@@ -9,7 +9,7 @@ This guide explains how to use Nix to set up a reproducible development environm
|
||||
- **Reproducible environment**: Everyone gets the same versions of tools and compilers
|
||||
- **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment
|
||||
- **No system pollution**: Dependencies are isolated and don't affect your system packages
|
||||
- **Multiple compiler versions**: Easily switch between different GCC and Clang versions
|
||||
- **Consistent compilers**: The GCC and Clang shells use the same versions as CI
|
||||
- **Quick setup**: Get started with a single command
|
||||
- **Works on Linux and macOS**: Consistent experience across platforms
|
||||
|
||||
@@ -31,8 +31,8 @@ This will:
|
||||
|
||||
- Download and set up all required development tools (CMake, Ninja, Conan, etc.)
|
||||
- Configure the appropriate compiler for your platform:
|
||||
- **Linux**: GCC 15.2 (provided by Nix)
|
||||
- **macOS**: Apple Clang (your system compiler)
|
||||
- **Linux**: GCC (provided by Nix)
|
||||
- **macOS**: Clang (provided by Nix)
|
||||
|
||||
The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster.
|
||||
|
||||
@@ -40,12 +40,12 @@ The first time you run this command, it will take a few minutes to download and
|
||||
|
||||
- **Linux**: `nix develop` gives you a shell with all the tooling necessary to
|
||||
develop xrpld and with GCC 15.2 (also provided by Nix). There are no caveats.
|
||||
- **macOS**: `nix develop` gives you a full environment too. The compiler is
|
||||
your system-wide Apple Clang, while every other tool — including Conan — is
|
||||
provided by Nix. Conan has no binary in the Nix cache for macOS, so it is
|
||||
built from source the first time you enter the shell, which makes the initial
|
||||
setup slower (this is handled automatically; see
|
||||
[`nix/devshell.nix`](../../nix/devshell.nix)).
|
||||
- **macOS**: `nix develop` gives you a full environment too, with Clang (and
|
||||
every other tool, including Conan) provided by Nix. To use your system-wide
|
||||
Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in
|
||||
the Nix cache for macOS, so it is built from source the first time you enter
|
||||
the shell, which makes the initial setup slower (this is handled
|
||||
automatically; see [`nix/devshell.nix`](../../nix/devshell.nix)).
|
||||
|
||||
> [!TIP]
|
||||
> To avoid typing `--experimental-features 'nix-command flakes'` every time, you can permanently enable flakes by creating `~/.config/nix/nix.conf`:
|
||||
@@ -62,7 +62,9 @@ The first time you run this command, it will take a few minutes to download and
|
||||
|
||||
### Choosing a different compiler
|
||||
|
||||
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#gcc15`.
|
||||
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`.
|
||||
The `.#gcc` and `.#clang` shells provide the same GCC and Clang versions used in CI
|
||||
(pinned in [`nix/packages.nix`](../../nix/packages.nix)).
|
||||
Use `nix flake show` to see all the available development shells.
|
||||
|
||||
Use `nix develop .#no-compiler` to use the compiler from your system.
|
||||
@@ -70,11 +72,11 @@ Use `nix develop .#no-compiler` to use the compiler from your system.
|
||||
### Example Usage
|
||||
|
||||
```bash
|
||||
# Use GCC 14
|
||||
nix develop .#gcc14
|
||||
# Use GCC (same version as CI)
|
||||
nix develop .#gcc
|
||||
|
||||
# Use Clang 19
|
||||
nix develop .#clang19
|
||||
# Use Clang (same version as CI)
|
||||
nix develop .#clang
|
||||
|
||||
# Use default for your platform
|
||||
nix develop
|
||||
@@ -112,7 +114,15 @@ Once inside the Nix development shell, follow the standard [build instructions](
|
||||
|
||||
[direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory.
|
||||
|
||||
This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`. To use it, install direnv for your shell, then add an `.envrc` containing `use flake` at the repository root and run `direnv allow`.
|
||||
This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`.
|
||||
|
||||
The repository already ships an `.envrc` at its root that activates the Nix flake development shell, so you don't need to create one. To use it:
|
||||
|
||||
1. [Install direnv](https://direnv.net/docs/installation.html) and [hook it into your shell](https://direnv.net/docs/hook.html) (bash, zsh, fish, …). Installing [nix-direnv](https://github.com/nix-community/nix-direnv) as well is recommended: it caches the shell so that activation is near-instant after the first run.
|
||||
2. Run `direnv allow` once in the repository root. direnv will then load (and reload) the Nix development shell automatically whenever you enter the directory.
|
||||
|
||||
> [!NOTE]
|
||||
> direnv only caches the `.direnv` directory (already listed in `.gitignore`); no other repository files are affected.
|
||||
|
||||
## Conan and Prebuilt Packages
|
||||
|
||||
|
||||
@@ -595,7 +595,7 @@ template <std::size_t Bits, typename Tag>
|
||||
[[nodiscard]] constexpr bool
|
||||
operator==(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
|
||||
{
|
||||
return (lhs <=> rhs) == 0;
|
||||
return (lhs <=> rhs) == 0; // NOLINT(modernize-use-nullptr)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h> // IWYU pragma: keep
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
|
||||
#include <cstdint>
|
||||
@@ -288,7 +290,7 @@ public:
|
||||
// Called when the owner count changes
|
||||
// This is required to support PaymentSandbox
|
||||
virtual void
|
||||
adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next)
|
||||
adjustOwnerCountHook(AccountID const& account, OwnerCounts const& cur, OwnerCounts const& next)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -411,6 +413,23 @@ public:
|
||||
emptyDirDelete(Keylet const& directory);
|
||||
};
|
||||
|
||||
/** Bundles the mutable ledger view and the transaction being applied.
|
||||
|
||||
Passed together to avoid threading two separate parameters through every
|
||||
helper that needs both the view (for state reads/writes) and the
|
||||
transaction (for field inspection and metadata).
|
||||
|
||||
Both members are non-owning references; the caller is responsible for
|
||||
ensuring that the referenced objects outlive the ApplyViewContext.
|
||||
|
||||
TODO: replace with ApplyContext after it's untangled with xrpl/tx
|
||||
*/
|
||||
struct ApplyViewContext
|
||||
{
|
||||
ApplyView& view;
|
||||
STTx const& tx;
|
||||
};
|
||||
|
||||
namespace directory {
|
||||
/** Helper functions for managing low-level directory operations.
|
||||
These are not part of the ApplyView interface.
|
||||
|
||||
70
include/xrpl/ledger/OwnerCounts.h
Normal file
70
include/xrpl/ledger/OwnerCounts.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STInteger.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
struct OwnerCounts
|
||||
{
|
||||
std::uint32_t owner = 0;
|
||||
std::uint32_t sponsored = 0;
|
||||
std::uint32_t sponsoring = 0;
|
||||
|
||||
OwnerCounts() = default;
|
||||
OwnerCounts(SLE::const_ref sle)
|
||||
: owner(sle->at(sfOwnerCount))
|
||||
, sponsored(sle->at(sfSponsoredOwnerCount))
|
||||
, sponsoring(sle->at(sfSponsoringOwnerCount))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
owner >= sponsored,
|
||||
"xrpl::OwnerCounts : OwnerCount must be greater than or equal to "
|
||||
"SponsoredOwnerCount");
|
||||
XRPL_ASSERT(sle->getType() == ltACCOUNT_ROOT, "xrpl::OwnerCounts : sle is AccountRoot");
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t
|
||||
count() const
|
||||
{
|
||||
std::int64_t const x = static_cast<std::int64_t>(owner) - sponsored + sponsoring;
|
||||
if (x < 0)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::OwnerCounts::count : count less than zero");
|
||||
return 0;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
if (x > std::numeric_limits<std::uint32_t>::max())
|
||||
return std::numeric_limits<std::uint32_t>::max(); // LCOV_EXCL_LINE
|
||||
return static_cast<std::uint32_t>(x);
|
||||
}
|
||||
|
||||
auto
|
||||
operator<=>(OwnerCounts const& o) const
|
||||
{
|
||||
if (auto cmp = count() <=> o.count(); cmp != 0) // NOLINT(modernize-use-nullptr)
|
||||
return cmp;
|
||||
if (auto cmp = owner <=> o.owner; cmp != 0) // NOLINT(modernize-use-nullptr)
|
||||
return cmp;
|
||||
if (auto cmp = sponsored <=> o.sponsored; cmp != 0) // NOLINT(modernize-use-nullptr)
|
||||
return cmp;
|
||||
return sponsoring <=> o.sponsoring;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(OwnerCounts const& o) const
|
||||
{
|
||||
return this == &o ||
|
||||
(owner == o.owner && sponsored == o.sponsored && sponsoring == o.sponsoring);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/RawView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/detail/ApplyViewBase.h>
|
||||
@@ -107,12 +108,12 @@ public:
|
||||
issuerSelfDebitMPT(MPTIssue const& issue, std::uint64_t amount, std::int64_t origBalance);
|
||||
|
||||
void
|
||||
ownerCount(AccountID const& id, std::uint32_t cur, std::uint32_t next);
|
||||
ownerCount(AccountID const& id, OwnerCounts const& cur, OwnerCounts const& next);
|
||||
|
||||
// Get the adjusted owner count. Since DeferredCredits is meant to be used
|
||||
// in payments, and payments only decrease owner counts, return the max
|
||||
// remembered owner count.
|
||||
[[nodiscard]] std::optional<std::uint32_t>
|
||||
[[nodiscard]] std::optional<OwnerCounts>
|
||||
ownerCount(AccountID const& id) const;
|
||||
|
||||
void
|
||||
@@ -124,7 +125,7 @@ private:
|
||||
|
||||
std::map<KeyIOU, ValueIOU> creditsIOU_;
|
||||
std::map<MPTID, IssuerValueMPT> creditsMPT_;
|
||||
std::map<AccountID, std::uint32_t> ownerCounts_;
|
||||
std::map<AccountID, OwnerCounts> ownerCounts_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -218,10 +219,11 @@ public:
|
||||
override;
|
||||
|
||||
void
|
||||
adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next) override;
|
||||
adjustOwnerCountHook(AccountID const& account, OwnerCounts const& cur, OwnerCounts const& next)
|
||||
override;
|
||||
|
||||
[[nodiscard]] std::uint32_t
|
||||
ownerCountHook(AccountID const& account, std::uint32_t count) const override;
|
||||
[[nodiscard]] OwnerCounts
|
||||
ownerCountHook(AccountID const& account, OwnerCounts const& count) const override;
|
||||
|
||||
/** Apply changes to base view.
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/beast/hash/uhash.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/detail/ReadViewFwdRange.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
@@ -13,6 +14,7 @@
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
@@ -189,8 +191,8 @@ public:
|
||||
// changes that accounts make during a payment. `ownerCountHook` adjusts the
|
||||
// ownerCount so it returns the max value of the ownerCount so far.
|
||||
// This is required to support PaymentSandbox.
|
||||
[[nodiscard]] virtual std::uint32_t
|
||||
ownerCountHook(AccountID const& account, std::uint32_t count) const
|
||||
[[nodiscard]] virtual OwnerCounts
|
||||
ownerCountHook(AccountID const& account, OwnerCounts const& count) const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -210,8 +210,7 @@ canWithdraw(ReadView const& view, STTx const& tx);
|
||||
|
||||
[[nodiscard]] TER
|
||||
doWithdraw(
|
||||
ApplyView& view,
|
||||
STTx const& tx,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& senderAcct,
|
||||
AccountID const& dstAcct,
|
||||
AccountID const& sourceAcct,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@@ -26,21 +27,293 @@ namespace xrpl {
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen(ReadView const& view, AccountID const& issuer);
|
||||
|
||||
// Calculate liquid XRP balance for an account.
|
||||
// This function may be used to calculate the amount of XRP that
|
||||
// the holder is able to freely spend. It subtracts reserve requirements.
|
||||
//
|
||||
// ownerCountAdj adjusts the owner count in case the caller calculates
|
||||
// before ledger entries are added or removed. Positive to add, negative
|
||||
// to subtract.
|
||||
//
|
||||
// @param ownerCountAdj positive to add to count, negative to reduce count.
|
||||
/** Calculate liquid XRP balance for an account.
|
||||
*
|
||||
* This function may be used to calculate the amount of XRP that
|
||||
* the holder is able to freely spend. It subtracts reserve requirements.
|
||||
*
|
||||
* ownerCountAdj adjusts the owner count in case the caller calculates
|
||||
* before ledger entries are added or removed. Positive to add, negative
|
||||
* to subtract.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param id The account ID to check
|
||||
* @param ownerCountAdj Positive to add to count, negative to reduce count
|
||||
* @param j Journal for logging
|
||||
* @return The liquid XRP amount available to the account
|
||||
*/
|
||||
[[nodiscard]] XRPAmount
|
||||
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
|
||||
|
||||
/** Adjust the owner count up or down. */
|
||||
struct Adjustment
|
||||
{
|
||||
std::int32_t ownerCountDelta = 0;
|
||||
std::int32_t accountCountDelta = 0;
|
||||
};
|
||||
|
||||
/** Returns the account reserve, in drops.
|
||||
*
|
||||
* Actual owner count can be adjusted by delta in ownerCountAdj
|
||||
* Actual reserve count can be adjusted by delta in accountCountAdj
|
||||
* The reserve is calculated as:
|
||||
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
||||
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param sle The ledger entry for the account
|
||||
* @param j Journal for logging
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
||||
* subtract.
|
||||
* @return The account reserve amount in drops
|
||||
*/
|
||||
[[nodiscard]] XRPAmount
|
||||
accountReserve(ReadView const& view, SLE::const_ref sle, beast::Journal j, Adjustment adj = {});
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of SLE.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param id The account ID
|
||||
* @param j Journal for logging
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
||||
* subtract.
|
||||
* @return The account reserve amount in drops
|
||||
*/
|
||||
[[nodiscard]] inline XRPAmount
|
||||
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
|
||||
{
|
||||
return accountReserve(view, view.read(keylet::account(id)), j, adj);
|
||||
}
|
||||
|
||||
/** Check if an account has sufficient reserve.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param tx The transaction being processed
|
||||
* @param accSle The account's ledger entry
|
||||
* @param accBalance The account's balance
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
||||
* subtract.
|
||||
* @param j Journal for logging (default: null sink)
|
||||
* @param insufReserveCode The transaction result code to return if the reserve is insufficient
|
||||
* (default: tecINSUFFICIENT_RESERVE).
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] 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, deriving the sponsor internally.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getEffectiveTxReserveSponsor(ctx, accSle) instead of taking it explicitly. Use this
|
||||
* in the common case where the sponsor is simply the transaction's reserve
|
||||
* sponsor for accSle. Callers that must force the account's-own-reserve branch
|
||||
* (passing a null sponsor) or supply a different sponsor should use the
|
||||
* explicit overload above.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accSle The account's ledger entry
|
||||
* @param accBalance The account's balance
|
||||
* @param adj Reserve adjustments (owner/account count deltas)
|
||||
* @param j Journal for logging (default: null sink)
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkReserve(
|
||||
ApplyViewContext ctx,
|
||||
SLE::const_ref accSle,
|
||||
XRPAmount accBalance,
|
||||
Adjustment adj,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
/** Return number of the objects which reserve is covered by the account(sle) (so called "owner
|
||||
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
|
||||
*
|
||||
* @param sle The account's ledger entry
|
||||
* @param j Journal for logging
|
||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||
* @return The adjusted owner count
|
||||
*/
|
||||
std::uint32_t
|
||||
ownerCount(SLE::const_ref sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
|
||||
|
||||
/** Increase owner-count fields when the caller supplies the sponsor.
|
||||
*
|
||||
* This helper does not create a ledger object. It updates reserve accounting
|
||||
* after the caller has created/updated an object.
|
||||
* If sponsorSle is provided, this also adjusts the account's sponsored count
|
||||
* and the sponsor's sponsoring count.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param count Amount to add to the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
adjustOwnerCount(ApplyView& view, SLE::ref sle, std::int32_t amount, beast::Journal j);
|
||||
increaseOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/** Increase owner-count fields, deriving the tx reserve sponsor internally.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getEffectiveTxReserveSponsor(ctx, accountSle) instead of taking it explicitly. Use
|
||||
* this when the sponsor is the transaction's reserve sponsor for accountSle
|
||||
* (the common create path). Deletion paths, which derive the sponsor from an
|
||||
* object's sfSponsor field, should keep using the explicit overload.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param count Amount to add to the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
increaseOwnerCount(
|
||||
ApplyViewContext ctx,
|
||||
SLE::ref accountSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of SLE references.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param account The account ID
|
||||
* @param sponsor The optional sponsor account ID
|
||||
* @param count Amount to add to the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
inline void
|
||||
increaseOwnerCount(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
std::optional<AccountID> const& sponsor,
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
increaseOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(account)),
|
||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
||||
count,
|
||||
j);
|
||||
}
|
||||
|
||||
/** Decrease owner-count fields when the caller supplies the sponsor.
|
||||
*
|
||||
* This helper does not delete a ledger object. It updates reserve accounting
|
||||
* after the caller has removed an owner-counted reserve, or for special
|
||||
* owner-count changes whose sponsor cannot be derived from an object's
|
||||
* sfSponsor field.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param count Amount to remove from the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
decreaseOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of SLE references.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param account The account ID
|
||||
* @param sponsor The optional sponsor account ID
|
||||
* @param count Amount to remove from the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
inline void
|
||||
decreaseOwnerCount(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
std::optional<AccountID> const& sponsor,
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
decreaseOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(account)),
|
||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
||||
count,
|
||||
j);
|
||||
}
|
||||
|
||||
/** Decrease owner-count fields for an existing ledger object.
|
||||
*
|
||||
* This helper derives the reserve sponsor from objectSle's sfSponsor field,
|
||||
* then updates the same owner-count fields as decreaseOwnerCount. Use this
|
||||
* when removing an existing object whose reserve sponsor is stored on that
|
||||
* object.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param objectSle The object's ledger entry
|
||||
* @param count Amount to remove from the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
decreaseOwnerCountForObject(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref objectSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/** Convenience overload that accepts AccountID instead of account SLE reference.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param account The account ID
|
||||
* @param objectSle The object's ledger entry
|
||||
* @param count Amount to remove from the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
inline void
|
||||
decreaseOwnerCountForObject(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
SLE::ref objectSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
SLE::ref accountSle = view.peek(keylet::account(account));
|
||||
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
|
||||
}
|
||||
|
||||
/** Adjust a LoanBroker's owner count.
|
||||
*
|
||||
* A LoanBroker's sfOwnerCount tracks the number of outstanding loans on
|
||||
* that broker; it is not a reserve-backed owner count and is distinct
|
||||
* from the broker's pseudo-account's owner count. Loans can never carry a
|
||||
* reserve sponsor (LoanSet rejects reserve sponsorship at preflight), so
|
||||
* this never involves sponsor accounting and never invokes the
|
||||
* ownerCountHook used for ACCOUNT_ROOT reserve tracking.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param brokerSle The LoanBroker's ledger entry
|
||||
* @param delta Amount to add (positive) or remove (negative) from the count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
adjustLoanBrokerOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref brokerSle,
|
||||
std::int32_t delta,
|
||||
beast::Journal j);
|
||||
|
||||
/** Returns IOU issuer transfer fee as Rate. Rate specifies
|
||||
* the fee as fractions of 1 billion. For example, 1% transfer rate
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Concepts.h>
|
||||
@@ -22,17 +23,15 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowUnlockApplyHelper(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
Rate lockedRate,
|
||||
SLE::ref sleDest,
|
||||
STAmount const& xrpBalance,
|
||||
XRPAmount xrpBalance,
|
||||
STAmount const& amount,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
@@ -43,10 +42,10 @@ escrowUnlockApplyHelper(
|
||||
template <>
|
||||
inline TER
|
||||
escrowUnlockApplyHelper<Issue>(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
Rate lockedRate,
|
||||
SLE::ref sleDest,
|
||||
STAmount const& xrpBalance,
|
||||
XRPAmount xrpBalance,
|
||||
STAmount const& amount,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
@@ -66,16 +65,26 @@ escrowUnlockApplyHelper<Issue>(
|
||||
if (receiverIssuer)
|
||||
return tesSUCCESS;
|
||||
|
||||
if (!view.exists(trustLineKey) && createAsset)
|
||||
if (!ctx.view.exists(trustLineKey) && createAsset)
|
||||
{
|
||||
// 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 sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
if (auto const ret = checkReserve(
|
||||
ctx,
|
||||
sleDest,
|
||||
xrpBalance,
|
||||
*sponsorSle,
|
||||
{.ownerCountDelta = 1},
|
||||
journal,
|
||||
tecNO_LINE_INSUF_RESERVE);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
JLOG(journal.trace()) << "Trust line does not exist. "
|
||||
"Insufficient reserve to create line.";
|
||||
|
||||
return tecNO_LINE_INSUF_RESERVE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Currency const currency = issue.currency;
|
||||
@@ -83,7 +92,7 @@ escrowUnlockApplyHelper<Issue>(
|
||||
initialBalance.get<Issue>().account = noAccount();
|
||||
|
||||
if (TER const ter = trustCreate(
|
||||
view, // payment sandbox
|
||||
ctx.view, // payment sandbox
|
||||
recvLow, // is dest low?
|
||||
issuer, // source
|
||||
receiver, // destination
|
||||
@@ -97,19 +106,20 @@ escrowUnlockApplyHelper<Issue>(
|
||||
Issue(currency, receiver), // limit of zero
|
||||
0, // quality in
|
||||
0, // quality out
|
||||
*sponsorSle, // sponsor
|
||||
journal); // journal
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
view.update(sleDest);
|
||||
ctx.view.update(sleDest);
|
||||
}
|
||||
|
||||
if (!view.exists(trustLineKey) && !receiverIssuer)
|
||||
if (!ctx.view.exists(trustLineKey) && !receiverIssuer)
|
||||
return tecNO_LINE;
|
||||
|
||||
auto const xferRate = transferRate(view, amount);
|
||||
auto const xferRate = transferRate(ctx.view, amount);
|
||||
// update if issuer rate is less than locked rate
|
||||
if (xferRate < lockedRate)
|
||||
lockedRate = xferRate;
|
||||
@@ -137,7 +147,7 @@ escrowUnlockApplyHelper<Issue>(
|
||||
// of the funds
|
||||
if (!createAsset)
|
||||
{
|
||||
auto const sleRippleState = view.peek(trustLineKey);
|
||||
auto const sleRippleState = ctx.view.peek(trustLineKey);
|
||||
if (!sleRippleState)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -163,7 +173,7 @@ escrowUnlockApplyHelper<Issue>(
|
||||
// if destination is not the issuer then transfer funds
|
||||
if (!receiverIssuer)
|
||||
{
|
||||
auto const ter = directSendNoFee(view, issuer, receiver, finalAmt, true, journal);
|
||||
auto const ter = directSendNoFee(ctx.view, issuer, receiver, finalAmt, true, journal);
|
||||
if (!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
}
|
||||
@@ -173,10 +183,10 @@ escrowUnlockApplyHelper<Issue>(
|
||||
template <>
|
||||
inline TER
|
||||
escrowUnlockApplyHelper<MPTIssue>(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
Rate lockedRate,
|
||||
SLE::ref sleDest,
|
||||
STAmount const& xrpBalance,
|
||||
XRPAmount xrpBalance,
|
||||
STAmount const& amount,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
@@ -189,27 +199,32 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
|
||||
auto const mptID = amount.get<MPTIssue>().getMptID();
|
||||
auto const issuanceKey = keylet::mptokenIssuance(mptID);
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer)
|
||||
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
|
||||
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
|
||||
{
|
||||
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
|
||||
xrpBalance < view.fees().accountReserve(ownerCount + 1))
|
||||
{
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
if (auto const ter = createMPToken(view, mptID, receiver, 0); !isTesSuccess(ter))
|
||||
if (auto const ret = checkReserve(
|
||||
ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// update owner count.
|
||||
adjustOwnerCount(view, sleDest, 1, journal);
|
||||
increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal);
|
||||
}
|
||||
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && !receiverIssuer)
|
||||
if (!ctx.view.exists(mptKeylet) && !receiverIssuer)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
auto const xferRate = transferRate(view, amount);
|
||||
auto const xferRate = transferRate(ctx.view, amount);
|
||||
// update if issuer rate is less than locked rate
|
||||
if (xferRate < lockedRate)
|
||||
lockedRate = xferRate;
|
||||
@@ -232,11 +247,11 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
finalAmt = amount.value() - xferFee;
|
||||
}
|
||||
return unlockEscrowMPT(
|
||||
view,
|
||||
ctx.view,
|
||||
sender,
|
||||
receiver,
|
||||
finalAmt,
|
||||
view.rules().enabled(fixTokenEscrowV1) ? amount : finalAmt,
|
||||
ctx.view.rules().enabled(fixTokenEscrowV1) ? amount : finalAmt,
|
||||
journal);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ canAddHolding(ReadView const& view, MPTIssue const& mptIssue);
|
||||
|
||||
[[nodiscard]] TER
|
||||
authorizeMPToken(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
XRPAmount const& priorBalance,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
@@ -117,7 +117,7 @@ requireAuth(
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
enforceMPTokenAuthorization(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
XRPAmount const& priorBalance,
|
||||
@@ -203,7 +203,7 @@ canMPTTradeAndTransfer(
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
MPTIssue const& mptIssue,
|
||||
@@ -211,7 +211,7 @@ addEmptyHolding(
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
MPTIssue const& mptIssue,
|
||||
beast::Journal journal);
|
||||
@@ -243,6 +243,7 @@ createMPToken(
|
||||
ApplyView& view,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
SLE::ref sponsorSle,
|
||||
std::uint32_t const flags);
|
||||
|
||||
TER
|
||||
@@ -250,6 +251,7 @@ checkCreateMPT(
|
||||
xrpl::ApplyView& view,
|
||||
xrpl::MPTIssue const& mptIssue,
|
||||
xrpl::AccountID const& holder,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
31
include/xrpl/ledger/helpers/OracleHelpers.h
Normal file
31
include/xrpl/ledger/helpers/OracleHelpers.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STArray.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
constexpr std::uint32_t kMinOracleReserveCount = 1;
|
||||
constexpr std::uint32_t kMaxOracleReserveCount = 2;
|
||||
constexpr std::size_t kOracleReserveCountThreshold = 5;
|
||||
|
||||
template <typename T>
|
||||
requires requires(T const& t) { t.size(); }
|
||||
inline std::uint32_t
|
||||
calculateOracleReserve(T const& priceDataSeries)
|
||||
{
|
||||
return priceDataSeries.size() > kOracleReserveCountThreshold ? kMaxOracleReserveCount
|
||||
: kMinOracleReserveCount;
|
||||
}
|
||||
|
||||
inline std::uint32_t
|
||||
calculateOracleReserve(SLE::const_ref oracleSle)
|
||||
{
|
||||
return calculateOracleReserve(oracleSle->getFieldArray(sfPriceDataSeries));
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -156,6 +156,7 @@ trustCreate(
|
||||
// Issuer should be the account being set.
|
||||
std::uint32_t uQualityIn,
|
||||
std::uint32_t uQualityOut,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] TER
|
||||
@@ -178,6 +179,7 @@ issueIOU(
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
Issue const& issue,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] TER
|
||||
@@ -235,7 +237,7 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
|
||||
/// canAddHolding() in preflight with the same View and Asset
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
Issue const& issue,
|
||||
@@ -243,7 +245,7 @@ addEmptyHolding(
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
Issue const& issue,
|
||||
beast::Journal journal);
|
||||
|
||||
184
include/xrpl/ledger/helpers/SponsorHelpers.h
Normal file
184
include/xrpl/ledger/helpers/SponsorHelpers.h
Normal file
@@ -0,0 +1,184 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/** Whether the given transaction type may use reserve sponsorship (v1).
|
||||
*
|
||||
* Reserve sponsorship is restricted to an explicit allow-list of transaction
|
||||
* types; all others reject spfSponsorReserve at preflight.
|
||||
*/
|
||||
bool
|
||||
isReserveSponsorAllowed(TxType txType);
|
||||
|
||||
/** Whether the transaction's fee is sponsored (sfSponsor present + spfSponsorFee set). */
|
||||
inline bool
|
||||
isFeeSponsored(STTx const& tx)
|
||||
{
|
||||
return tx.isFieldPresent(sfSponsor) && ((tx.getFieldU32(sfSponsorFlags) & spfSponsorFee) != 0u);
|
||||
}
|
||||
|
||||
/** Whether the transaction's reserve is sponsored (sfSponsor present + spfSponsorReserve set). */
|
||||
inline bool
|
||||
isReserveSponsored(STTx const& tx)
|
||||
{
|
||||
return tx.isFieldPresent(sfSponsor) &&
|
||||
((tx.getFieldU32(sfSponsorFlags) & spfSponsorReserve) != 0u);
|
||||
}
|
||||
|
||||
/** Return the AccountID of the transaction's reserve sponsor, or nullopt if unsponsored. */
|
||||
std::optional<AccountID>
|
||||
getTxReserveSponsorID(STTx const& tx);
|
||||
|
||||
/** Return a mutable SLE for the transaction's reserve sponsor account.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @return The sponsor account SLE, a null pointer if the tx is not
|
||||
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
||||
* be loaded (an already-checked invariant).
|
||||
*/
|
||||
std::expected<SLE::pointer, TER>
|
||||
getTxReserveSponsor(ApplyViewContext ctx);
|
||||
|
||||
/** Return a read-only SLE for the transaction's reserve sponsor account.
|
||||
*
|
||||
* @param view The ledger read view
|
||||
* @param tx The transaction to inspect
|
||||
* @return The sponsor account SLE, a null pointer if the tx is not
|
||||
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
||||
* be loaded (an already-checked invariant).
|
||||
*/
|
||||
std::expected<SLE::const_pointer, TER>
|
||||
getTxReserveSponsor(ReadView const& view, STTx const& tx);
|
||||
|
||||
/** The transaction's reserve sponsor for the given account, if applicable.
|
||||
*
|
||||
* A reserve sponsor only covers the transaction submitter's own objects, so
|
||||
* this returns the tx reserve sponsor SLE only when accountSle is the tx's own
|
||||
* (non-pseudo) account; otherwise it returns a null sponsor pointer. This is
|
||||
* the single source of truth for the "sponsor applies to tx.Account only" rule
|
||||
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accountSle The account whose sponsor is being resolved
|
||||
* @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the
|
||||
* sponsor account cannot be loaded (an already-checked invariant)
|
||||
*/
|
||||
[[nodiscard]] std::expected<SLE::pointer, TER>
|
||||
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::const_ref accountSle);
|
||||
|
||||
/** Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
|
||||
*/
|
||||
std::optional<AccountID>
|
||||
getLedgerEntryReserveSponsorID(SLE::const_ref sle, SF_ACCOUNT const& field = sfSponsor);
|
||||
|
||||
/** Return a mutable SLE for the reserve sponsor recorded on a ledger entry.
|
||||
*
|
||||
* Reads the sponsor AccountID from @p field on @p sle and peeks the
|
||||
* corresponding account root in @p view.
|
||||
*
|
||||
* @param view The mutable apply view
|
||||
* @param sle The ledger entry whose sponsor field is inspected
|
||||
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
|
||||
* @return The sponsor account SLE, or a null pointer if the entry is unsponsored.
|
||||
*/
|
||||
SLE::pointer
|
||||
getLedgerEntryReserveSponsor(
|
||||
ApplyView& view,
|
||||
SLE::const_ref sle,
|
||||
SF_ACCOUNT const& field = sfSponsor);
|
||||
|
||||
/** Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
|
||||
*
|
||||
* Sets @p field on @p sle to the AccountID from @p sponsorSle. A no-op when
|
||||
* @p sponsorSle is null (unsponsored). For RippleState entries the field must
|
||||
* be sfHighSponsor or sfLowSponsor; for all other entry types it must be
|
||||
* sfSponsor.
|
||||
*
|
||||
* @param sle The ledger entry to stamp
|
||||
* @param sponsorSle The sponsor's account root SLE (null → no-op)
|
||||
* @param field The sponsor field to set (defaults to sfSponsor)
|
||||
*/
|
||||
void
|
||||
addSponsorToLedgerEntry(
|
||||
SLE::ref sle,
|
||||
SLE::const_ref sponsorSle,
|
||||
SF_ACCOUNT const& field = sfSponsor);
|
||||
|
||||
/** Stamp the transaction's reserve sponsor onto a newly-created ledger entry.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getTxReserveSponsor(ctx) instead of taking it explicitly. A no-op when the
|
||||
* transaction is not reserve-sponsored. The entry is assumed to be owned by
|
||||
* the transaction submitter, which is the only account a tx reserve sponsor
|
||||
* can cover.
|
||||
*/
|
||||
void
|
||||
addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::ref sle, SF_ACCOUNT const& field = sfSponsor);
|
||||
|
||||
/** Remove the reserve sponsor field from a ledger entry.
|
||||
*
|
||||
* A no-op when @p field is not present on @p sle. For RippleState entries
|
||||
* the field must be sfHighSponsor or sfLowSponsor; for all other entry types
|
||||
* it must be sfSponsor.
|
||||
*
|
||||
* @param sle The ledger entry to modify
|
||||
* @param field The sponsor field to clear (defaults to sfSponsor)
|
||||
*/
|
||||
void
|
||||
removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field = sfSponsor);
|
||||
|
||||
/** Whether @p account is the owner of a ledger entry for sponsorship purposes.
|
||||
*
|
||||
* Ownership rules vary by entry type. For RippleState entries the owner is
|
||||
* whichever side of the trust line holds the reserve. For credentials, the
|
||||
* owner is the subject once accepted and the issuer before acceptance.
|
||||
*
|
||||
* @param view The ledger read view (used for SignerList lookup)
|
||||
* @param sle The ledger entry whose owner is checked
|
||||
* @param account The candidate account to match against
|
||||
* @return true if @p account owns @p sle, false otherwise.
|
||||
*/
|
||||
bool
|
||||
isLedgerEntryOwner(ReadView const& view, SLE const& sle, AccountID const& account);
|
||||
|
||||
/** Whether this ledger entry type can have a reserve sponsor attached to it. */
|
||||
bool
|
||||
isLedgerEntrySupportedBySponsorship(SLE const& sle);
|
||||
|
||||
/** Return the number of owner-count units the ledger entry consumes.
|
||||
*
|
||||
* Most entries cost 1. Exceptions: Oracles scale with their price-data series
|
||||
* size, Vaults cost 2 (vault + pseudo-account), and legacy SignerList entries
|
||||
* (pre-MultiSignReserve) cost 2 + signer count.
|
||||
*/
|
||||
std::uint32_t
|
||||
getLedgerEntryOwnerCount(SLE const& sle);
|
||||
|
||||
/** Return the SField used to store the reserve sponsor for @p owner on @p sle.
|
||||
*
|
||||
* For most entry types this is sfSponsor. RippleState entries use
|
||||
* sfHighSponsor or sfLowSponsor depending on which side of the trust line
|
||||
* @p owner holds.
|
||||
*
|
||||
* @param sle The ledger entry
|
||||
* @param owner The account whose sponsor field is needed
|
||||
* @return sfHighSponsor, sfLowSponsor, or sfSponsor as appropriate.
|
||||
*/
|
||||
SF_ACCOUNT const&
|
||||
getLedgerEntrySponsorField(SLE const& sle, AccountID const& owner);
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
@@ -302,7 +303,7 @@ canAddHolding(ReadView const& view, Asset const& asset);
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
Asset const& asset,
|
||||
@@ -310,7 +311,7 @@ addEmptyHolding(
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
Asset const& asset,
|
||||
beast::Journal journal);
|
||||
@@ -371,6 +372,7 @@ accountSend(
|
||||
AccountID const& to,
|
||||
STAmount const& saAmount,
|
||||
beast::Journal j,
|
||||
SLE::ref sponsorSle = {},
|
||||
WaiveTransferFee waiveFee = WaiveTransferFee::No,
|
||||
AllowMPTOverflow allowOverflow = AllowMPTOverflow::No);
|
||||
|
||||
|
||||
@@ -74,9 +74,9 @@ operator==(Book const& lhs, Book const& rhs)
|
||||
[[nodiscard]] constexpr std::weak_ordering
|
||||
operator<=>(Book const& lhs, Book const& rhs)
|
||||
{
|
||||
if (auto const c{lhs.in <=> rhs.in}; c != 0)
|
||||
if (auto const c{lhs.in <=> rhs.in}; c != 0) // NOLINT(modernize-use-nullptr)
|
||||
return c;
|
||||
if (auto const c{lhs.out <=> rhs.out}; c != 0)
|
||||
if (auto const c{lhs.out <=> rhs.out}; c != 0) // NOLINT(modernize-use-nullptr)
|
||||
return c;
|
||||
|
||||
// Manually compare optionals
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -39,13 +38,13 @@ struct Fees
|
||||
|
||||
/** Returns the account reserve given the owner count, in drops.
|
||||
|
||||
The reserve is calculated as the reserve base plus
|
||||
the reserve increment times the number of increments.
|
||||
The reserve is calculated as the reserve base times the number of accounts plus the reserve
|
||||
increment times the number of increments.
|
||||
*/
|
||||
[[nodiscard]] XRPAmount
|
||||
accountReserve(std::size_t ownerCount) const
|
||||
accountReserve(std::uint32_t ownerCount, std::uint32_t accountCount) const
|
||||
{
|
||||
return reserve + ownerCount * increment;
|
||||
return (reserve * accountCount) + (increment * ownerCount);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
@@ -142,6 +141,10 @@ ticket(uint256 const& key)
|
||||
Keylet
|
||||
signerList(AccountID const& account) noexcept;
|
||||
|
||||
/** A Sponsorship */
|
||||
Keylet
|
||||
sponsorship(AccountID const& sponsor, AccountID const& sponsee) noexcept;
|
||||
|
||||
/** A Check */
|
||||
/** @{ */
|
||||
Keylet
|
||||
@@ -251,17 +254,6 @@ amm(uint256 const& amm) noexcept;
|
||||
Keylet
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept;
|
||||
|
||||
Keylet
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
|
||||
|
||||
// `seq` is stored as `sfXChainClaimID` in the object
|
||||
Keylet
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq);
|
||||
|
||||
// `seq` is stored as `sfXChainAccountCreateCount` in the object
|
||||
Keylet
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq);
|
||||
|
||||
Keylet
|
||||
did(AccountID const& account) noexcept;
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ operator==(Issue const& lhs, Issue const& rhs)
|
||||
[[nodiscard]] constexpr std::weak_ordering
|
||||
operator<=>(Issue const& lhs, Issue const& rhs)
|
||||
{
|
||||
if (auto const c{lhs.currency <=> rhs.currency}; c != 0)
|
||||
if (auto const c{lhs.currency <=> rhs.currency}; c != 0) // NOLINT(modernize-use-nullptr)
|
||||
return c;
|
||||
|
||||
if (isXRP(lhs.currency))
|
||||
|
||||
@@ -208,7 +208,11 @@ enum LedgerEntryType : std::uint16_t {
|
||||
LEDGER_OBJECT(Loan, \
|
||||
LSF_FLAG(lsfLoanDefault, 0x00010000) \
|
||||
LSF_FLAG(lsfLoanImpaired, 0x00020000) \
|
||||
LSF_FLAG(lsfLoanOverpayment, 0x00040000)) /* True, loan allows overpayments */
|
||||
LSF_FLAG(lsfLoanOverpayment, 0x00040000)) /* True, loan allows overpayments */ \
|
||||
\
|
||||
LEDGER_OBJECT(Sponsorship, \
|
||||
LSF_FLAG(lsfSponsorshipRequireSignForFee, 0x00010000) \
|
||||
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000))
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ class STBitString;
|
||||
template <class>
|
||||
class STInteger;
|
||||
class STNumber;
|
||||
class STXChainBridge;
|
||||
class STVector256;
|
||||
class STCurrency;
|
||||
|
||||
@@ -71,7 +70,7 @@ class STCurrency;
|
||||
STYPE(STI_UINT384, 22) \
|
||||
STYPE(STI_UINT512, 23) \
|
||||
STYPE(STI_ISSUE, 24) \
|
||||
STYPE(STI_XCHAIN_BRIDGE, 25) \
|
||||
/* 25 is unused */ \
|
||||
STYPE(STI_CURRENCY, 26) \
|
||||
\
|
||||
/* high-level types */ \
|
||||
@@ -353,7 +352,6 @@ using SF_CURRENCY = TypedField<STCurrency>;
|
||||
using SF_NUMBER = TypedField<STNumber>;
|
||||
using SF_VL = TypedField<STBlob>;
|
||||
using SF_VECTOR256 = TypedField<STVector256>;
|
||||
using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/SOTemplate.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
@@ -229,10 +230,10 @@ public:
|
||||
[[nodiscard]] AccountID
|
||||
getAccountID(SField const& field) const;
|
||||
|
||||
/** The account responsible for the fee and authorization: the delegate when
|
||||
/** The account responsible for the authorization: the delegate when
|
||||
sfDelegate is present, otherwise the account. */
|
||||
[[nodiscard]] AccountID
|
||||
getFeePayer() const;
|
||||
getInitiator() const;
|
||||
|
||||
[[nodiscard]] Blob
|
||||
getFieldVL(SField const& field) const;
|
||||
|
||||
@@ -141,6 +141,9 @@ public:
|
||||
[[nodiscard]] std::vector<uint256> const&
|
||||
getBatchTransactionIDs() const;
|
||||
|
||||
[[nodiscard]] AccountID
|
||||
getFeePayerID() const;
|
||||
|
||||
private:
|
||||
/** Check the signature.
|
||||
@param rules The current ledger rules.
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class Serializer;
|
||||
class STObject;
|
||||
|
||||
class STXChainBridge final : public STBase, public CountedObject<STXChainBridge>
|
||||
{
|
||||
STAccount lockingChainDoor_{sfLockingChainDoor};
|
||||
STIssue lockingChainIssue_{sfLockingChainIssue};
|
||||
STAccount issuingChainDoor_{sfIssuingChainDoor};
|
||||
STIssue issuingChainIssue_{sfIssuingChainIssue};
|
||||
|
||||
public:
|
||||
using value_type = STXChainBridge;
|
||||
|
||||
enum class ChainType { Locking, Issuing };
|
||||
|
||||
static ChainType
|
||||
otherChain(ChainType ct);
|
||||
|
||||
static ChainType
|
||||
srcChain(bool wasLockingChainSend);
|
||||
|
||||
static ChainType
|
||||
dstChain(bool wasLockingChainSend);
|
||||
|
||||
STXChainBridge();
|
||||
|
||||
explicit STXChainBridge(SField const& name);
|
||||
|
||||
STXChainBridge(STXChainBridge const& rhs) = default;
|
||||
|
||||
STXChainBridge(STObject const& o);
|
||||
|
||||
STXChainBridge(
|
||||
AccountID const& srcChainDoor,
|
||||
Issue const& srcChainIssue,
|
||||
AccountID const& dstChainDoor,
|
||||
Issue const& dstChainIssue);
|
||||
|
||||
explicit STXChainBridge(json::Value const& v);
|
||||
|
||||
explicit STXChainBridge(SField const& name, json::Value const& v);
|
||||
|
||||
explicit STXChainBridge(SerialIter& sit, SField const& name);
|
||||
|
||||
STXChainBridge&
|
||||
operator=(STXChainBridge const& rhs) = default;
|
||||
|
||||
[[nodiscard]] std::string
|
||||
getText() const override;
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
lockingChainDoor() const;
|
||||
|
||||
[[nodiscard]] Issue const&
|
||||
lockingChainIssue() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
issuingChainDoor() const;
|
||||
|
||||
[[nodiscard]] Issue const&
|
||||
issuingChainIssue() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
door(ChainType ct) const;
|
||||
|
||||
[[nodiscard]] Issue const&
|
||||
issue(ChainType ct) const;
|
||||
|
||||
[[nodiscard]] SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
[[nodiscard]] json::Value getJson(JsonOptions) const override;
|
||||
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDefault() const override;
|
||||
|
||||
[[nodiscard]] value_type const&
|
||||
value() const noexcept;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<STXChainBridge>
|
||||
construct(SerialIter&, SField const& name);
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
STBase*
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend bool
|
||||
operator==(STXChainBridge const& lhs, STXChainBridge const& rhs);
|
||||
|
||||
friend bool
|
||||
operator<(STXChainBridge const& lhs, STXChainBridge const& rhs);
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator==(STXChainBridge const& lhs, STXChainBridge const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.lockingChainDoor_,
|
||||
lhs.lockingChainIssue_,
|
||||
lhs.issuingChainDoor_,
|
||||
lhs.issuingChainIssue_) ==
|
||||
std::tie(
|
||||
rhs.lockingChainDoor_,
|
||||
rhs.lockingChainIssue_,
|
||||
rhs.issuingChainDoor_,
|
||||
rhs.issuingChainIssue_);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(STXChainBridge const& lhs, STXChainBridge const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.lockingChainDoor_,
|
||||
lhs.lockingChainIssue_,
|
||||
lhs.issuingChainDoor_,
|
||||
lhs.issuingChainIssue_) <
|
||||
std::tie(
|
||||
rhs.lockingChainDoor_,
|
||||
rhs.lockingChainIssue_,
|
||||
rhs.issuingChainDoor_,
|
||||
rhs.issuingChainIssue_);
|
||||
}
|
||||
|
||||
inline AccountID const&
|
||||
STXChainBridge::lockingChainDoor() const
|
||||
{
|
||||
return lockingChainDoor_.value();
|
||||
};
|
||||
|
||||
inline Issue const&
|
||||
STXChainBridge::lockingChainIssue() const
|
||||
{
|
||||
return lockingChainIssue_.value().get<Issue>();
|
||||
};
|
||||
|
||||
inline AccountID const&
|
||||
STXChainBridge::issuingChainDoor() const
|
||||
{
|
||||
return issuingChainDoor_.value();
|
||||
};
|
||||
|
||||
inline Issue const&
|
||||
STXChainBridge::issuingChainIssue() const
|
||||
{
|
||||
return issuingChainIssue_.value().get<Issue>();
|
||||
};
|
||||
|
||||
inline STXChainBridge::value_type const&
|
||||
STXChainBridge::value() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AccountID const&
|
||||
STXChainBridge::door(ChainType ct) const
|
||||
{
|
||||
if (ct == ChainType::Locking)
|
||||
return lockingChainDoor();
|
||||
return issuingChainDoor();
|
||||
}
|
||||
|
||||
inline Issue const&
|
||||
STXChainBridge::issue(ChainType ct) const
|
||||
{
|
||||
if (ct == ChainType::Locking)
|
||||
return lockingChainIssue();
|
||||
return issuingChainIssue();
|
||||
}
|
||||
|
||||
inline STXChainBridge::ChainType
|
||||
STXChainBridge::otherChain(ChainType ct)
|
||||
{
|
||||
if (ct == ChainType::Locking)
|
||||
return ChainType::Issuing;
|
||||
return ChainType::Locking;
|
||||
}
|
||||
|
||||
inline STXChainBridge::ChainType
|
||||
STXChainBridge::srcChain(bool wasLockingChainSend)
|
||||
{
|
||||
if (wasLockingChainSend)
|
||||
return ChainType::Locking;
|
||||
return ChainType::Issuing;
|
||||
}
|
||||
|
||||
inline STXChainBridge::ChainType
|
||||
STXChainBridge::dstChain(bool wasLockingChainSend)
|
||||
{
|
||||
if (wasLockingChainSend)
|
||||
return ChainType::Issuing;
|
||||
return ChainType::Locking;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -225,6 +225,7 @@ enum TERcodes : TERUnderlyingType {
|
||||
// create a pseudo-account
|
||||
terNO_DELEGATE_PERMISSION, // Delegate does not have permission
|
||||
terLOCKED, // MPT is locked
|
||||
terNO_PERMISSION, // No permission but retry
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -368,6 +369,7 @@ enum TECcodes : TERUnderlyingType {
|
||||
// reclaimed after those networks reset.
|
||||
tecNO_DELEGATE_PERMISSION = 198,
|
||||
tecBAD_PROOF = 199,
|
||||
tecNO_SPONSOR_PERMISSION = 200,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -102,7 +102,8 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TRANSACTION(Payment, \
|
||||
TF_FLAG(tfNoRippleDirect, 0x00010000) \
|
||||
TF_FLAG(tfPartialPayment, 0x00020000) \
|
||||
TF_FLAG(tfLimitQuality, 0x00040000), \
|
||||
TF_FLAG(tfLimitQuality, 0x00040000) \
|
||||
TF_FLAG(tfSponsorCreatedAccount, 0x00080000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(TrustSet, \
|
||||
@@ -141,7 +142,7 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfMPTCanTrade, lsfMPTCanTrade) \
|
||||
TF_FLAG(tfMPTCanTransfer, lsfMPTCanTransfer) \
|
||||
TF_FLAG(tfMPTCanClawback, lsfMPTCanClawback) \
|
||||
TF_FLAG(tfMPTCanHoldConfidentialBalance, lsfMPTCanHoldConfidentialBalance), \
|
||||
TF_FLAG(tfMPTCanHoldConfidentialBalance, lsfMPTCanHoldConfidentialBalance), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(MPTokenAuthorize, \
|
||||
@@ -180,10 +181,6 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfClawTwoAssets, 0x00000001), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(XChainModifyBridge, \
|
||||
TF_FLAG(tfClearAccountCreateAmount, 0x00010000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(VaultCreate, \
|
||||
TF_FLAG(tfVaultPrivate, lsfVaultPrivate) \
|
||||
TF_FLAG(tfVaultShareNonTransferable, 0x00020000), \
|
||||
@@ -215,6 +212,20 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfLoanDefault, 0x00010000) \
|
||||
TF_FLAG(tfLoanImpair, 0x00020000) \
|
||||
TF_FLAG(tfLoanUnimpair, 0x00040000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(SponsorshipSet, \
|
||||
TF_FLAG(tfSponsorshipSetRequireSignForFee, 0x00010000) \
|
||||
TF_FLAG(tfSponsorshipClearRequireSignForFee, 0x00020000) \
|
||||
TF_FLAG(tfSponsorshipSetRequireSignForReserve, 0x00040000) \
|
||||
TF_FLAG(tfSponsorshipClearRequireSignForReserve, 0x00080000) \
|
||||
TF_FLAG(tfDeleteObject, 0x00100000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(SponsorshipTransfer, \
|
||||
TF_FLAG(tfSponsorshipEnd, 0x00010000) \
|
||||
TF_FLAG(tfSponsorshipCreate, 0x00020000) \
|
||||
TF_FLAG(tfSponsorshipReassign, 0x00040000), \
|
||||
MASK_ADJ(0))
|
||||
|
||||
// clang-format on
|
||||
@@ -444,6 +455,12 @@ getAsfFlagMap()
|
||||
#pragma pop_macro("ACCOUNTSET_FLAG_TO_MAP")
|
||||
#pragma pop_macro("ACCOUNTSET_FLAGS")
|
||||
|
||||
// Sponsor flags (spf)
|
||||
|
||||
inline constexpr FlagValue spfSponsorFee = 1;
|
||||
inline constexpr FlagValue spfSponsorReserve = 2;
|
||||
inline constexpr FlagValue spfSponsorFlagMask = ~(spfSponsorFee | spfSponsorReserve);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
// NOLINTEND(readability-identifier-naming)
|
||||
|
||||
@@ -1,471 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/vector.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace Attestations {
|
||||
|
||||
struct AttestationBase
|
||||
{
|
||||
// Account associated with the public key
|
||||
AccountID attestationSignerAccount;
|
||||
// Public key from the witness server attesting to the event
|
||||
PublicKey publicKey;
|
||||
// Signature from the witness server attesting to the event
|
||||
Buffer signature;
|
||||
// Account on the sending chain that triggered the event (sent the
|
||||
// transaction)
|
||||
AccountID sendingAccount;
|
||||
// Amount transferred on the sending chain
|
||||
STAmount sendingAmount;
|
||||
// Account on the destination chain that collects a share of the attestation
|
||||
// reward
|
||||
AccountID rewardAccount;
|
||||
// Amount was transferred on the locking chain
|
||||
bool wasLockingChainSend;
|
||||
|
||||
explicit AttestationBase(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend);
|
||||
|
||||
AttestationBase(AttestationBase const&) = default;
|
||||
|
||||
virtual ~AttestationBase() = default;
|
||||
|
||||
AttestationBase&
|
||||
operator=(AttestationBase const&) = default;
|
||||
|
||||
// verify that the signature attests to the data.
|
||||
[[nodiscard]] bool
|
||||
verify(STXChainBridge const& bridge) const;
|
||||
|
||||
protected:
|
||||
explicit AttestationBase(STObject const& o);
|
||||
explicit AttestationBase(json::Value const& v);
|
||||
|
||||
[[nodiscard]] static bool
|
||||
equalHelper(AttestationBase const& lhs, AttestationBase const& rhs);
|
||||
|
||||
[[nodiscard]] static bool
|
||||
sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs);
|
||||
|
||||
void
|
||||
addHelper(STObject& o) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] virtual std::vector<std::uint8_t>
|
||||
message(STXChainBridge const& bridge) const = 0;
|
||||
};
|
||||
|
||||
// Attest to a regular cross-chain transfer
|
||||
struct AttestationClaim : AttestationBase
|
||||
{
|
||||
std::uint64_t claimID;
|
||||
std::optional<AccountID> dst;
|
||||
|
||||
explicit AttestationClaim(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
explicit AttestationClaim(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
explicit AttestationClaim(STObject const& o);
|
||||
explicit AttestationClaim(json::Value const& v);
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
// return true if the two attestations attest to the same thing
|
||||
[[nodiscard]] bool
|
||||
sameEvent(AttestationClaim const& rhs) const;
|
||||
|
||||
[[nodiscard]] static std::vector<std::uint8_t>
|
||||
message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimID,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
[[nodiscard]] bool
|
||||
validAmounts() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::vector<std::uint8_t>
|
||||
message(STXChainBridge const& bridge) const override;
|
||||
|
||||
friend bool
|
||||
operator==(AttestationClaim const& lhs, AttestationClaim const& rhs);
|
||||
};
|
||||
|
||||
struct CmpByClaimID
|
||||
{
|
||||
bool
|
||||
operator()(AttestationClaim const& lhs, AttestationClaim const& rhs) const
|
||||
{
|
||||
return lhs.claimID < rhs.claimID;
|
||||
}
|
||||
};
|
||||
|
||||
// Attest to a cross-chain transfer that creates an account
|
||||
struct AttestationCreateAccount : AttestationBase
|
||||
{
|
||||
// createCount on the sending chain. This is the value of the `CreateCount`
|
||||
// field of the bridge on the sending chain when the transaction was
|
||||
// executed.
|
||||
std::uint64_t createCount;
|
||||
// Account to create on the destination chain
|
||||
AccountID toCreate;
|
||||
// Total amount of the reward pool
|
||||
STAmount rewardAmount;
|
||||
|
||||
explicit AttestationCreateAccount(STObject const& o);
|
||||
|
||||
explicit AttestationCreateAccount(json::Value const& v);
|
||||
|
||||
explicit AttestationCreateAccount(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate);
|
||||
|
||||
explicit AttestationCreateAccount(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate);
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
// return true if the two attestations attest to the same thing
|
||||
[[nodiscard]] bool
|
||||
sameEvent(AttestationCreateAccount const& rhs) const;
|
||||
|
||||
friend bool
|
||||
operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs);
|
||||
|
||||
[[nodiscard]] static std::vector<std::uint8_t>
|
||||
message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& dst);
|
||||
|
||||
[[nodiscard]] bool
|
||||
validAmounts() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::vector<std::uint8_t>
|
||||
message(STXChainBridge const& bridge) const override;
|
||||
};
|
||||
|
||||
struct CmpByCreateCount
|
||||
{
|
||||
bool
|
||||
operator()(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) const
|
||||
{
|
||||
return lhs.createCount < rhs.createCount;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace Attestations
|
||||
|
||||
// Result when checking when two attestation match.
|
||||
enum class AttestationMatch {
|
||||
// One of the fields doesn't match, and it isn't the dst field
|
||||
NonDstMismatch,
|
||||
// all of the fields match, except the dst field
|
||||
MatchExceptDst,
|
||||
// all of the fields match
|
||||
Match
|
||||
};
|
||||
|
||||
struct XChainClaimAttestation
|
||||
{
|
||||
using TSignedAttestation = Attestations::AttestationClaim;
|
||||
static SField const& arrayFieldName;
|
||||
|
||||
AccountID keyAccount;
|
||||
PublicKey publicKey;
|
||||
STAmount amount;
|
||||
AccountID rewardAccount;
|
||||
bool wasLockingChainSend;
|
||||
std::optional<AccountID> dst;
|
||||
|
||||
struct MatchFields
|
||||
{
|
||||
STAmount amount;
|
||||
bool wasLockingChainSend;
|
||||
std::optional<AccountID> dst;
|
||||
MatchFields(TSignedAttestation const& att);
|
||||
MatchFields(STAmount a, bool b, std::optional<AccountID> const& d)
|
||||
: amount{std::move(a)}, wasLockingChainSend{b}, dst{d}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
explicit XChainClaimAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
explicit XChainClaimAttestation(
|
||||
STAccount const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAccount const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<STAccount> const& dst);
|
||||
|
||||
explicit XChainClaimAttestation(TSignedAttestation const& claimAtt);
|
||||
|
||||
explicit XChainClaimAttestation(STObject const& o);
|
||||
|
||||
explicit XChainClaimAttestation(json::Value const& v);
|
||||
|
||||
[[nodiscard]] AttestationMatch
|
||||
match(MatchFields const& rhs) const;
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
friend bool
|
||||
operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs);
|
||||
};
|
||||
|
||||
struct XChainCreateAccountAttestation
|
||||
{
|
||||
using TSignedAttestation = Attestations::AttestationCreateAccount;
|
||||
static SField const& arrayFieldName;
|
||||
|
||||
AccountID keyAccount;
|
||||
PublicKey publicKey;
|
||||
STAmount amount;
|
||||
STAmount rewardAmount;
|
||||
AccountID rewardAccount;
|
||||
bool wasLockingChainSend;
|
||||
AccountID dst;
|
||||
|
||||
struct MatchFields
|
||||
{
|
||||
STAmount amount;
|
||||
STAmount rewardAmount;
|
||||
bool wasLockingChainSend;
|
||||
AccountID dst;
|
||||
|
||||
MatchFields(TSignedAttestation const& att);
|
||||
};
|
||||
|
||||
explicit XChainCreateAccountAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
AccountID const& dst);
|
||||
|
||||
explicit XChainCreateAccountAttestation(TSignedAttestation const& claimAtt);
|
||||
|
||||
explicit XChainCreateAccountAttestation(STObject const& o);
|
||||
|
||||
explicit XChainCreateAccountAttestation(json::Value const& v);
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
[[nodiscard]] AttestationMatch
|
||||
match(MatchFields const& rhs) const;
|
||||
|
||||
friend bool
|
||||
operator==(
|
||||
XChainCreateAccountAttestation const& lhs,
|
||||
XChainCreateAccountAttestation const& rhs);
|
||||
};
|
||||
|
||||
// Attestations from witness servers for a particular claim ID and bridge.
|
||||
// Only one attestation per signature is allowed.
|
||||
template <class TAttestation>
|
||||
class XChainAttestationsBase
|
||||
{
|
||||
public:
|
||||
using AttCollection = std::vector<TAttestation>;
|
||||
|
||||
private:
|
||||
// Set a max number of allowed attestations to limit the amount of memory
|
||||
// allocated and processing time. This number is much larger than the actual
|
||||
// number of attestation a server would ever expect.
|
||||
static constexpr std::uint32_t kMaxAttestations = 256;
|
||||
AttCollection attestations_;
|
||||
|
||||
protected:
|
||||
// Prevent slicing to the base class
|
||||
~XChainAttestationsBase() = default;
|
||||
|
||||
public:
|
||||
XChainAttestationsBase() = default;
|
||||
XChainAttestationsBase(XChainAttestationsBase const& rhs) = default;
|
||||
XChainAttestationsBase&
|
||||
operator=(XChainAttestationsBase const& rhs) = default;
|
||||
|
||||
explicit XChainAttestationsBase(AttCollection&& sigs);
|
||||
|
||||
explicit XChainAttestationsBase(json::Value const& v);
|
||||
|
||||
explicit XChainAttestationsBase(STArray const& arr);
|
||||
|
||||
[[nodiscard]] STArray
|
||||
toSTArray() const;
|
||||
|
||||
[[nodiscard]] AttCollection::const_iterator
|
||||
begin() const;
|
||||
|
||||
[[nodiscard]] AttCollection::const_iterator
|
||||
end() const;
|
||||
|
||||
AttCollection::iterator
|
||||
begin();
|
||||
|
||||
AttCollection::iterator
|
||||
end();
|
||||
|
||||
template <class F>
|
||||
std::size_t
|
||||
eraseIf(F&& f);
|
||||
|
||||
[[nodiscard]] std::size_t
|
||||
size() const;
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const;
|
||||
|
||||
[[nodiscard]] AttCollection const&
|
||||
attestations() const;
|
||||
|
||||
template <class T>
|
||||
void
|
||||
emplaceBack(T&& att);
|
||||
};
|
||||
|
||||
template <class TAttestation>
|
||||
[[nodiscard]] inline bool
|
||||
operator==(
|
||||
XChainAttestationsBase<TAttestation> const& lhs,
|
||||
XChainAttestationsBase<TAttestation> const& rhs)
|
||||
{
|
||||
return lhs.attestations() == rhs.attestations();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline XChainAttestationsBase<TAttestation>::AttCollection const&
|
||||
XChainAttestationsBase<TAttestation>::attestations() const
|
||||
{
|
||||
return attestations_;
|
||||
};
|
||||
|
||||
template <class TAttestation>
|
||||
template <class T>
|
||||
inline void
|
||||
XChainAttestationsBase<TAttestation>::emplaceBack(T&& att)
|
||||
{
|
||||
attestations_.emplace_back(std::forward<T>(att));
|
||||
};
|
||||
|
||||
template <class TAttestation>
|
||||
template <class F>
|
||||
inline std::size_t
|
||||
XChainAttestationsBase<TAttestation>::eraseIf(F&& f)
|
||||
{
|
||||
return std::erase_if(attestations_, std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline std::size_t
|
||||
XChainAttestationsBase<TAttestation>::size() const
|
||||
{
|
||||
return attestations_.size();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline bool
|
||||
XChainAttestationsBase<TAttestation>::empty() const
|
||||
{
|
||||
return attestations_.empty();
|
||||
}
|
||||
|
||||
class XChainClaimAttestations final : public XChainAttestationsBase<XChainClaimAttestation>
|
||||
{
|
||||
using TBase = XChainAttestationsBase<XChainClaimAttestation>;
|
||||
using TBase::TBase;
|
||||
};
|
||||
|
||||
class XChainCreateAccountAttestations final
|
||||
: public XChainAttestationsBase<XChainCreateAccountAttestation>
|
||||
{
|
||||
using TBase = XChainAttestationsBase<XChainCreateAccountAttestation>;
|
||||
using TBase::TBase;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -15,6 +15,7 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FEATURE(Sponsor, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(BatchV1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ConfidentialTransfer, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
@@ -54,13 +55,13 @@ XRPL_FIX (ReducedOffersV2, Supported::Yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(NFTokenMintOffer, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMv1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PreviousTxnID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::Obsolete)
|
||||
XRPL_FIX (EmptyDID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PriceOracle, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMOverflowOffer, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (FillOrKill, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::Obsolete)
|
||||
XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
|
||||
@@ -127,29 +127,32 @@ LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({
|
||||
\sa keylet::account
|
||||
*/
|
||||
LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfBalance, SoeRequired},
|
||||
{sfOwnerCount, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccountTxnID, SoeOptional},
|
||||
{sfRegularKey, SoeOptional},
|
||||
{sfEmailHash, SoeOptional},
|
||||
{sfWalletLocator, SoeOptional},
|
||||
{sfWalletSize, SoeOptional},
|
||||
{sfMessageKey, SoeOptional},
|
||||
{sfTransferRate, SoeOptional},
|
||||
{sfDomain, SoeOptional},
|
||||
{sfTickSize, SoeOptional},
|
||||
{sfTicketCount, SoeOptional},
|
||||
{sfNFTokenMinter, SoeOptional},
|
||||
{sfMintedNFTokens, SoeDefault},
|
||||
{sfBurnedNFTokens, SoeDefault},
|
||||
{sfFirstNFTokenSequence, SoeOptional},
|
||||
{sfAMMID, SoeOptional}, // pseudo-account designator
|
||||
{sfVaultID, SoeOptional}, // pseudo-account designator
|
||||
{sfLoanBrokerID, SoeOptional}, // pseudo-account designator
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfBalance, SoeRequired},
|
||||
{sfOwnerCount, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfAccountTxnID, SoeOptional},
|
||||
{sfRegularKey, SoeOptional},
|
||||
{sfEmailHash, SoeOptional},
|
||||
{sfWalletLocator, SoeOptional},
|
||||
{sfWalletSize, SoeOptional},
|
||||
{sfMessageKey, SoeOptional},
|
||||
{sfTransferRate, SoeOptional},
|
||||
{sfDomain, SoeOptional},
|
||||
{sfTickSize, SoeOptional},
|
||||
{sfTicketCount, SoeOptional},
|
||||
{sfNFTokenMinter, SoeOptional},
|
||||
{sfMintedNFTokens, SoeDefault},
|
||||
{sfBurnedNFTokens, SoeDefault},
|
||||
{sfFirstNFTokenSequence, SoeOptional},
|
||||
{sfSponsoredOwnerCount, SoeDefault},
|
||||
{sfSponsoringOwnerCount, SoeDefault},
|
||||
{sfSponsoringAccountCount, SoeDefault},
|
||||
{sfAMMID, SoeOptional}, // pseudo-account designator
|
||||
{sfVaultID, SoeOptional}, // pseudo-account designator
|
||||
{sfLoanBrokerID, SoeOptional}, // pseudo-account designator
|
||||
}))
|
||||
|
||||
/** A ledger object which contains a list of object identifiers.
|
||||
@@ -203,23 +206,6 @@ LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, ({
|
||||
{sfHashes, SoeRequired},
|
||||
}))
|
||||
|
||||
/** The ledger object which lists details about sidechains.
|
||||
|
||||
\sa keylet::bridge
|
||||
*/
|
||||
LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, bridge, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfMinAccountCreateAmount, SoeOptional},
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfXChainAccountClaimCount, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes an offer on the DEX.
|
||||
|
||||
\sa keylet::offer
|
||||
@@ -252,22 +238,6 @@ LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preaut
|
||||
{sfAuthorizeCredentials, SoeOptional},
|
||||
}))
|
||||
|
||||
/** A claim id for a cross chain transaction.
|
||||
|
||||
\sa keylet::xChainClaimID
|
||||
*/
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_claim_id, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
{sfXChainClaimAttestations, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a bidirectional trust line.
|
||||
|
||||
@note Per Vinnie Falco this should be renamed to ltTRUST_LINE
|
||||
@@ -286,6 +256,8 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
{sfHighNode, SoeOptional},
|
||||
{sfHighQualityIn, SoeOptional},
|
||||
{sfHighQualityOut, SoeOptional},
|
||||
{sfHighSponsor, SoeOptional},
|
||||
{sfLowSponsor, SoeOptional},
|
||||
}))
|
||||
|
||||
/** The ledger object which lists the network's fee settings.
|
||||
@@ -308,20 +280,6 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
}))
|
||||
|
||||
/** A claim id for a cross chain create account transaction.
|
||||
|
||||
\sa keylet::xChainCreateAccountClaimID
|
||||
*/
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAccountClaimID, xchain_owned_create_account_claim_id, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfXChainCreateAccountAttestations, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object describing a single escrow.
|
||||
|
||||
\sa keylet::escrow
|
||||
@@ -616,5 +574,20 @@ LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
|
||||
{sfLoanScale, SoeDefault},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a sponsorship.
|
||||
\sa keylet::sponsorship
|
||||
*/
|
||||
LEDGER_ENTRY(ltSPONSORSHIP, 0x0090, Sponsorship, sponsorship, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwner, SoeRequired},
|
||||
{sfSponsee, SoeRequired},
|
||||
{sfFeeAmount, SoeOptional},
|
||||
{sfMaxFee, SoeOptional},
|
||||
{sfRemainingOwnerCount, SoeDefault},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfSponseeNode, SoeRequired},
|
||||
}))
|
||||
|
||||
#undef EXPAND
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
|
||||
@@ -23,7 +23,7 @@ TYPED_SFIELD(sfAssetScale, UINT8, 5)
|
||||
TYPED_SFIELD(sfTickSize, UINT8, 16)
|
||||
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
|
||||
TYPED_SFIELD(sfHookResult, UINT8, 18)
|
||||
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
|
||||
// 19 unused
|
||||
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
|
||||
|
||||
// 16-bit integers (common)
|
||||
@@ -114,6 +114,11 @@ TYPED_SFIELD(sfLateInterestRate, UINT32, 66) // 1/10 basis points (bi
|
||||
TYPED_SFIELD(sfCloseInterestRate, UINT32, 67) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfOverpaymentInterestRate, UINT32, 68) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfConfidentialBalanceVersion, UINT32, 69)
|
||||
TYPED_SFIELD(sfSponsoredOwnerCount, UINT32, 70)
|
||||
TYPED_SFIELD(sfSponsoringOwnerCount, UINT32, 71)
|
||||
TYPED_SFIELD(sfSponsoringAccountCount, UINT32, 72)
|
||||
TYPED_SFIELD(sfRemainingOwnerCount, UINT32, 73)
|
||||
TYPED_SFIELD(sfSponsorFlags, UINT32, 74)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
@@ -135,9 +140,7 @@ TYPED_SFIELD(sfHookOn, UINT64, 16)
|
||||
TYPED_SFIELD(sfHookInstructionCount, UINT64, 17)
|
||||
TYPED_SFIELD(sfHookReturnCode, UINT64, 18)
|
||||
TYPED_SFIELD(sfReferenceCount, UINT64, 19)
|
||||
TYPED_SFIELD(sfXChainClaimID, UINT64, 20)
|
||||
TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21)
|
||||
TYPED_SFIELD(sfXChainAccountClaimCount, UINT64, 22)
|
||||
// 20-22 unused
|
||||
TYPED_SFIELD(sfAssetPrice, UINT64, 23)
|
||||
TYPED_SFIELD(sfMaximumAmount, UINT64, 24, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
@@ -148,6 +151,7 @@ TYPED_SFIELD(sfLockedAmount, UINT64, 29, SField::kSmdBaseTen|SFie
|
||||
TYPED_SFIELD(sfVaultNode, UINT64, 30)
|
||||
TYPED_SFIELD(sfLoanBrokerNode, UINT64, 31)
|
||||
TYPED_SFIELD(sfConfidentialOutstandingAmount, UINT64, 32, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfSponseeNode, UINT64, 33)
|
||||
|
||||
// 128-bit
|
||||
TYPED_SFIELD(sfEmailHash, UINT128, 1)
|
||||
@@ -209,6 +213,7 @@ TYPED_SFIELD(sfLoanBrokerID, UINT256, 37,
|
||||
TYPED_SFIELD(sfLoanID, UINT256, 38)
|
||||
TYPED_SFIELD(sfReferenceHolding, UINT256, 39)
|
||||
TYPED_SFIELD(sfBlindingFactor, UINT256, 40)
|
||||
TYPED_SFIELD(sfObjectID, UINT256, 41)
|
||||
|
||||
// number (common)
|
||||
TYPED_SFIELD(sfNumber, NUMBER, 1)
|
||||
@@ -268,6 +273,8 @@ TYPED_SFIELD(sfPrice, AMOUNT, 28)
|
||||
TYPED_SFIELD(sfSignatureReward, AMOUNT, 29)
|
||||
TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
|
||||
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
|
||||
TYPED_SFIELD(sfFeeAmount, AMOUNT, 32)
|
||||
TYPED_SFIELD(sfMaxFee, AMOUNT, 33)
|
||||
|
||||
// variable length (common)
|
||||
TYPED_SFIELD(sfPublicKey, VL, 1)
|
||||
@@ -334,15 +341,15 @@ TYPED_SFIELD(sfDelegate, ACCOUNT, 12)
|
||||
|
||||
// account (uncommon)
|
||||
TYPED_SFIELD(sfHookAccount, ACCOUNT, 16)
|
||||
TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18)
|
||||
TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19)
|
||||
TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20)
|
||||
TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21)
|
||||
TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22)
|
||||
TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23)
|
||||
// 17-23 are unused
|
||||
TYPED_SFIELD(sfSubject, ACCOUNT, 24)
|
||||
TYPED_SFIELD(sfBorrower, ACCOUNT, 25)
|
||||
TYPED_SFIELD(sfCounterparty, ACCOUNT, 26)
|
||||
TYPED_SFIELD(sfSponsor, ACCOUNT, 27)
|
||||
TYPED_SFIELD(sfHighSponsor, ACCOUNT, 28)
|
||||
TYPED_SFIELD(sfLowSponsor, ACCOUNT, 29)
|
||||
TYPED_SFIELD(sfCounterpartySponsor, ACCOUNT, 30)
|
||||
TYPED_SFIELD(sfSponsee, ACCOUNT, 31)
|
||||
|
||||
// vector of 256-bit
|
||||
TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::kSmdNever)
|
||||
@@ -359,14 +366,10 @@ TYPED_SFIELD(sfBaseAsset, CURRENCY, 1)
|
||||
TYPED_SFIELD(sfQuoteAsset, CURRENCY, 2)
|
||||
|
||||
// issue
|
||||
TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1)
|
||||
TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2)
|
||||
// 1 and 2 are unused
|
||||
TYPED_SFIELD(sfAsset, ISSUE, 3)
|
||||
TYPED_SFIELD(sfAsset2, ISSUE, 4)
|
||||
|
||||
// bridge
|
||||
TYPED_SFIELD(sfXChainBridge, XCHAIN_BRIDGE, 1)
|
||||
|
||||
// inner object
|
||||
// OBJECT/1 is reserved for end of object
|
||||
UNTYPED_SFIELD(sfTransactionMetaData, OBJECT, 2)
|
||||
@@ -397,16 +400,14 @@ UNTYPED_SFIELD(sfHookGrant, OBJECT, 24)
|
||||
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)
|
||||
UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26)
|
||||
UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27)
|
||||
UNTYPED_SFIELD(sfXChainClaimProofSig, OBJECT, 28)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountProofSig, OBJECT, 29)
|
||||
UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31)
|
||||
// 28 to 31 unused
|
||||
UNTYPED_SFIELD(sfPriceData, OBJECT, 32)
|
||||
UNTYPED_SFIELD(sfCredential, OBJECT, 33)
|
||||
UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34)
|
||||
UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35)
|
||||
UNTYPED_SFIELD(sfBook, OBJECT, 36)
|
||||
UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 37, SField::kSmdDefault, SField::kNotSigning)
|
||||
UNTYPED_SFIELD(sfSponsorSignature, OBJECT, 38, SField::kSmdDefault, SField::kNotSigning)
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -430,9 +431,7 @@ UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17)
|
||||
UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18)
|
||||
UNTYPED_SFIELD(sfHookParameters, ARRAY, 19)
|
||||
UNTYPED_SFIELD(sfHookGrants, ARRAY, 20)
|
||||
UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
|
||||
// 23 unused
|
||||
// 21-23 unused
|
||||
UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24)
|
||||
UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25)
|
||||
UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26)
|
||||
|
||||
@@ -509,120 +509,7 @@ TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
}))
|
||||
|
||||
/** This transactions creates a crosschain sequence number */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/bridge/XChainBridge.h>
|
||||
#endif
|
||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transactions initiates a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfOtherChainDestination, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction completes a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfAmount, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction initiates a crosschain account create transaction */
|
||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction adds an attestation to a claim */
|
||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
CreateAcct,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction adds an attestation to an account */
|
||||
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46,
|
||||
XChainAddAccountCreateAttestation,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
CreateAcct,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction modifies a sidechain */
|
||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeOptional},
|
||||
{sfMinAccountCreateAmount, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transactions creates a sidechain */
|
||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfMinAccountCreateAmount, SoeOptional},
|
||||
}))
|
||||
// 41 to 48 are unused
|
||||
|
||||
/** This transaction type creates or updates a DID */
|
||||
#if TRANSACTION_INCLUDE
|
||||
@@ -1165,6 +1052,35 @@ TRANSACTION(ttCONFIDENTIAL_MPT_CLAWBACK, 89, ConfidentialMPTClawback,
|
||||
{sfZKProof, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction transfers sponsorship on an object/account. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/sponsor/SponsorshipTransfer.h>
|
||||
#endif
|
||||
TRANSACTION(ttSPONSORSHIP_TRANSFER, 90, SponsorshipTransfer,
|
||||
Delegation::NotDelegable,
|
||||
featureSponsor,
|
||||
NoPriv,
|
||||
({
|
||||
{sfObjectID, SoeOptional},
|
||||
{sfSponsee, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction creates a Sponsorship object. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/sponsor/SponsorshipSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttSPONSORSHIP_SET, 91, SponsorshipSet,
|
||||
Delegation::Delegable,
|
||||
featureSponsor,
|
||||
NoPriv,
|
||||
({
|
||||
{sfCounterpartySponsor, SoeOptional},
|
||||
{sfSponsee, SoeOptional},
|
||||
{sfFeeAmount, SoeOptional},
|
||||
{sfMaxFee, SoeOptional},
|
||||
{sfRemainingOwnerCount, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the status of the various amendments.
|
||||
|
||||
For details, see: https://xrpl.org/amendments.html
|
||||
|
||||
@@ -157,7 +157,6 @@ JSS(both); // in: Subscribe, Unsubscribe
|
||||
JSS(both_sides); // in: Subscribe, Unsubscribe
|
||||
JSS(branch); // out: server_info
|
||||
JSS(broadcast); // out: SubmitTransaction
|
||||
JSS(bridge_account); // in: LedgerEntry
|
||||
JSS(build_path); // in: TransactionSign
|
||||
JSS(build_version); // out: NetworkOPs
|
||||
JSS(cancel_after); // out: AccountChannels
|
||||
@@ -558,6 +557,9 @@ JSS(source_account); // in: PathRequest, RipplePathFind
|
||||
JSS(source_amount); // in: PathRequest, RipplePathFind
|
||||
JSS(source_currencies); // in: PathRequest, RipplePathFind
|
||||
JSS(source_tag); // out: AccountChannels
|
||||
JSS(sponsee); // in: LedgerEntry
|
||||
JSS(sponsor); // in: LedgerEntry
|
||||
JSS(sponsored); // in: AccountObjects
|
||||
JSS(stand_alone); // out: NetworkOPs
|
||||
JSS(standard_deviation); // out: get_aggregate_price
|
||||
JSS(start); // in: TxHistory
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
|
||||
@@ -447,6 +447,78 @@ public:
|
||||
return this->sle_->isFieldPresent(sfFirstNFTokenSequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponsoredOwnerCount (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getSponsoredOwnerCount() const
|
||||
{
|
||||
if (hasSponsoredOwnerCount())
|
||||
return this->sle_->at(sfSponsoredOwnerCount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSponsoredOwnerCount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSponsoredOwnerCount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfSponsoredOwnerCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponsoringOwnerCount (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getSponsoringOwnerCount() const
|
||||
{
|
||||
if (hasSponsoringOwnerCount())
|
||||
return this->sle_->at(sfSponsoringOwnerCount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSponsoringOwnerCount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSponsoringOwnerCount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfSponsoringOwnerCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponsoringAccountCount (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getSponsoringAccountCount() const
|
||||
{
|
||||
if (hasSponsoringAccountCount())
|
||||
return this->sle_->at(sfSponsoringAccountCount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSponsoringAccountCount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSponsoringAccountCount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfSponsoringAccountCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAMMID (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
@@ -786,6 +858,39 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponsoredOwnerCount (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
AccountRootBuilder&
|
||||
setSponsoredOwnerCount(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponsoredOwnerCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponsoringOwnerCount (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
AccountRootBuilder&
|
||||
setSponsoringOwnerCount(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponsoringOwnerCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponsoringAccountCount (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
AccountRootBuilder&
|
||||
setSponsoringAccountCount(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponsoringAccountCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAMMID (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class BridgeBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: Bridge
|
||||
*
|
||||
* Type: ltBRIDGE (0x0069)
|
||||
* RPC Name: bridge
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use BridgeBuilder to construct new ledger entries.
|
||||
*/
|
||||
class Bridge : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltBRIDGE;
|
||||
|
||||
/**
|
||||
* @brief Construct a Bridge ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit Bridge(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Bridge");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAccount() const
|
||||
{
|
||||
return this->sle_->at(sfAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->sle_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMinAccountCreateAmount() const
|
||||
{
|
||||
if (hasMinAccountCreateAmount())
|
||||
return this->sle_->at(sfMinAccountCreateAmount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMinAccountCreateAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMinAccountCreateAmount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfMinAccountCreateAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->sle_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->sle_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountCreateCount() const
|
||||
{
|
||||
return this->sle_->at(sfXChainAccountCreateCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountClaimCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountClaimCount() const
|
||||
{
|
||||
return this->sle_->at(sfXChainAccountClaimCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for Bridge ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class BridgeBuilder : public LedgerEntryBuilderBase<BridgeBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new BridgeBuilder with required fields.
|
||||
* @param account The sfAccount field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param xChainAccountCreateCount The sfXChainAccountCreateCount field value.
|
||||
* @param xChainAccountClaimCount The sfXChainAccountClaimCount field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
*/
|
||||
BridgeBuilder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& account,std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward,std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge,std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID,std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountCreateCount,std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountClaimCount,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq)
|
||||
: LedgerEntryBuilderBase<BridgeBuilder>(ltBRIDGE)
|
||||
{
|
||||
setAccount(account);
|
||||
setSignatureReward(signatureReward);
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setXChainAccountCreateCount(xChainAccountCreateCount);
|
||||
setXChainAccountClaimCount(xChainAccountClaimCount);
|
||||
setOwnerNode(ownerNode);
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a BridgeBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
BridgeBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltBRIDGE)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Bridge");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/** @brief Ledger entry-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setMinAccountCreateAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMinAccountCreateAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainAccountCreateCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountCreateCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountClaimCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainAccountClaimCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountClaimCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed Bridge wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
Bridge
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return Bridge{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -243,6 +243,54 @@ public:
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfHighQualityOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHighSponsor (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getHighSponsor() const
|
||||
{
|
||||
if (hasHighSponsor())
|
||||
return this->sle_->at(sfHighSponsor);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfHighSponsor is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasHighSponsor() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfHighSponsor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfLowSponsor (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getLowSponsor() const
|
||||
{
|
||||
if (hasLowSponsor())
|
||||
return this->sle_->at(sfLowSponsor);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfLowSponsor is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasLowSponsor() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfLowSponsor);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -410,6 +458,28 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHighSponsor (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
RippleStateBuilder&
|
||||
setHighSponsor(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfHighSponsor] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfLowSponsor (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
RippleStateBuilder&
|
||||
setLowSponsor(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfLowSponsor] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed RippleState wrapper.
|
||||
* @param index The ledger entry index.
|
||||
|
||||
344
include/xrpl/protocol_autogen/ledger_entries/Sponsorship.h
Normal file
344
include/xrpl/protocol_autogen/ledger_entries/Sponsorship.h
Normal file
@@ -0,0 +1,344 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class SponsorshipBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: Sponsorship
|
||||
*
|
||||
* Type: ltSPONSORSHIP (0x0090)
|
||||
* RPC Name: sponsorship
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use SponsorshipBuilder to construct new ledger entries.
|
||||
*/
|
||||
class Sponsorship : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltSPONSORSHIP;
|
||||
|
||||
/**
|
||||
* @brief Construct a Sponsorship ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit Sponsorship(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Sponsorship");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwner (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOwner() const
|
||||
{
|
||||
return this->sle_->at(sfOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponsee (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getSponsee() const
|
||||
{
|
||||
return this->sle_->at(sfSponsee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfFeeAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getFeeAmount() const
|
||||
{
|
||||
if (hasFeeAmount())
|
||||
return this->sle_->at(sfFeeAmount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfFeeAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasFeeAmount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfFeeAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMaxFee (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMaxFee() const
|
||||
{
|
||||
if (hasMaxFee())
|
||||
return this->sle_->at(sfMaxFee);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMaxFee is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMaxFee() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfMaxFee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfRemainingOwnerCount (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getRemainingOwnerCount() const
|
||||
{
|
||||
if (hasRemainingOwnerCount())
|
||||
return this->sle_->at(sfRemainingOwnerCount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfRemainingOwnerCount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasRemainingOwnerCount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfRemainingOwnerCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponseeNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getSponseeNode() const
|
||||
{
|
||||
return this->sle_->at(sfSponseeNode);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for Sponsorship ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class SponsorshipBuilder : public LedgerEntryBuilderBase<SponsorshipBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new SponsorshipBuilder with required fields.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
* @param owner The sfOwner field value.
|
||||
* @param sponsee The sfSponsee field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param sponseeNode The sfSponseeNode field value.
|
||||
*/
|
||||
SponsorshipBuilder(std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq,std::decay_t<typename SF_ACCOUNT::type::value_type> const& owner,std::decay_t<typename SF_ACCOUNT::type::value_type> const& sponsee,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT64::type::value_type> const& sponseeNode)
|
||||
: LedgerEntryBuilderBase<SponsorshipBuilder>(ltSPONSORSHIP)
|
||||
{
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
setOwner(owner);
|
||||
setSponsee(sponsee);
|
||||
setOwnerNode(ownerNode);
|
||||
setSponseeNode(sponseeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a SponsorshipBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
SponsorshipBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltSPONSORSHIP)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Sponsorship");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/** @brief Ledger entry-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwner (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setOwner(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwner] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponsee (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setSponsee(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponsee] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFeeAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setFeeAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfFeeAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMaxFee (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setMaxFee(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMaxFee] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfRemainingOwnerCount (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setRemainingOwnerCount(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfRemainingOwnerCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponseeNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipBuilder&
|
||||
setSponseeNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponseeNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed Sponsorship wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
Sponsorship
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return Sponsorship{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -1,312 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class XChainOwnedClaimIDBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: XChainOwnedClaimID
|
||||
*
|
||||
* Type: ltXCHAIN_OWNED_CLAIM_ID (0x0071)
|
||||
* RPC Name: xchain_owned_claim_id
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use XChainOwnedClaimIDBuilder to construct new ledger entries.
|
||||
*/
|
||||
class XChainOwnedClaimID : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltXCHAIN_OWNED_CLAIM_ID;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedClaimID ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit XChainOwnedClaimID(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedClaimID");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAccount() const
|
||||
{
|
||||
return this->sle_->at(sfAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->sle_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->sle_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->sle_->at(sfOtherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimAttestations (SoeRequired)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
STArray const&
|
||||
getXChainClaimAttestations() const
|
||||
{
|
||||
return this->sle_->getFieldArray(sfXChainClaimAttestations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->sle_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainOwnedClaimID ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class XChainOwnedClaimIDBuilder : public LedgerEntryBuilderBase<XChainOwnedClaimIDBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainOwnedClaimIDBuilder with required fields.
|
||||
* @param account The sfAccount field value.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param xChainClaimAttestations The sfXChainClaimAttestations field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& account,std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge,std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID,std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource,STArray const& xChainClaimAttestations,std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq)
|
||||
: LedgerEntryBuilderBase<XChainOwnedClaimIDBuilder>(ltXCHAIN_OWNED_CLAIM_ID)
|
||||
{
|
||||
setAccount(account);
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setOtherChainSource(otherChainSource);
|
||||
setXChainClaimAttestations(xChainClaimAttestations);
|
||||
setSignatureReward(signatureReward);
|
||||
setOwnerNode(ownerNode);
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedClaimIDBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CLAIM_ID)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedClaimID");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/** @brief Ledger entry-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimAttestations (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setXChainClaimAttestations(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfXChainClaimAttestations, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed XChainOwnedClaimID wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
XChainOwnedClaimID
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return XChainOwnedClaimID{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -1,264 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class XChainOwnedCreateAccountClaimIDBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: XChainOwnedCreateAccountClaimID
|
||||
*
|
||||
* Type: ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID (0x0074)
|
||||
* RPC Name: xchain_owned_create_account_claim_id
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use XChainOwnedCreateAccountClaimIDBuilder to construct new ledger entries.
|
||||
*/
|
||||
class XChainOwnedCreateAccountClaimID : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedCreateAccountClaimID ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit XChainOwnedCreateAccountClaimID(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedCreateAccountClaimID");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAccount() const
|
||||
{
|
||||
return this->sle_->at(sfAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->sle_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountCreateCount() const
|
||||
{
|
||||
return this->sle_->at(sfXChainAccountCreateCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainCreateAccountAttestations (SoeRequired)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
STArray const&
|
||||
getXChainCreateAccountAttestations() const
|
||||
{
|
||||
return this->sle_->getFieldArray(sfXChainCreateAccountAttestations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainOwnedCreateAccountClaimID ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class XChainOwnedCreateAccountClaimIDBuilder : public LedgerEntryBuilderBase<XChainOwnedCreateAccountClaimIDBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainOwnedCreateAccountClaimIDBuilder with required fields.
|
||||
* @param account The sfAccount field value.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainAccountCreateCount The sfXChainAccountCreateCount field value.
|
||||
* @param xChainCreateAccountAttestations The sfXChainCreateAccountAttestations field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& account,std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge,std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountCreateCount,STArray const& xChainCreateAccountAttestations,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq)
|
||||
: LedgerEntryBuilderBase<XChainOwnedCreateAccountClaimIDBuilder>(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID)
|
||||
{
|
||||
setAccount(account);
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainAccountCreateCount(xChainAccountCreateCount);
|
||||
setXChainCreateAccountAttestations(xChainCreateAccountAttestations);
|
||||
setOwnerNode(ownerNode);
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedCreateAccountClaimIDBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedCreateAccountClaimID");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/** @brief Ledger entry-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setXChainAccountCreateCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountCreateCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainCreateAccountAttestations (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setXChainCreateAccountAttestations(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfXChainCreateAccountAttestations, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed XChainOwnedCreateAccountClaimID wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimID
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return XChainOwnedCreateAccountClaimID{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
290
include/xrpl/protocol_autogen/transactions/SponsorshipSet.h
Normal file
290
include/xrpl/protocol_autogen/transactions/SponsorshipSet.h
Normal file
@@ -0,0 +1,290 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class SponsorshipSetBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: SponsorshipSet
|
||||
*
|
||||
* Type: ttSPONSORSHIP_SET (91)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSponsor
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use SponsorshipSetBuilder to construct new transactions.
|
||||
*/
|
||||
class SponsorshipSet : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttSPONSORSHIP_SET;
|
||||
|
||||
/**
|
||||
* @brief Construct a SponsorshipSet transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit SponsorshipSet(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for SponsorshipSet");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfCounterpartySponsor (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getCounterpartySponsor() const
|
||||
{
|
||||
if (hasCounterpartySponsor())
|
||||
{
|
||||
return this->tx_->at(sfCounterpartySponsor);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfCounterpartySponsor is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasCounterpartySponsor() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfCounterpartySponsor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponsee (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getSponsee() const
|
||||
{
|
||||
if (hasSponsee())
|
||||
{
|
||||
return this->tx_->at(sfSponsee);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSponsee is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSponsee() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfSponsee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfFeeAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getFeeAmount() const
|
||||
{
|
||||
if (hasFeeAmount())
|
||||
{
|
||||
return this->tx_->at(sfFeeAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfFeeAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasFeeAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfFeeAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMaxFee (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMaxFee() const
|
||||
{
|
||||
if (hasMaxFee())
|
||||
{
|
||||
return this->tx_->at(sfMaxFee);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMaxFee is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMaxFee() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMaxFee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfRemainingOwnerCount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getRemainingOwnerCount() const
|
||||
{
|
||||
if (hasRemainingOwnerCount())
|
||||
{
|
||||
return this->tx_->at(sfRemainingOwnerCount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfRemainingOwnerCount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasRemainingOwnerCount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfRemainingOwnerCount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for SponsorshipSet transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class SponsorshipSetBuilder : public TransactionBuilderBase<SponsorshipSetBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new SponsorshipSetBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
SponsorshipSetBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<SponsorshipSetBuilder>(ttSPONSORSHIP_SET, account, sequence, fee)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a SponsorshipSetBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
SponsorshipSetBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttSPONSORSHIP_SET)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for SponsorshipSetBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfCounterpartySponsor (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setCounterpartySponsor(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfCounterpartySponsor] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponsee (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setSponsee(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponsee] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFeeAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setFeeAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfFeeAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMaxFee (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setMaxFee(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMaxFee] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfRemainingOwnerCount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipSetBuilder&
|
||||
setRemainingOwnerCount(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfRemainingOwnerCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the SponsorshipSet wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
SponsorshipSet
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return SponsorshipSet{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
179
include/xrpl/protocol_autogen/transactions/SponsorshipTransfer.h
Normal file
179
include/xrpl/protocol_autogen/transactions/SponsorshipTransfer.h
Normal file
@@ -0,0 +1,179 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class SponsorshipTransferBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: SponsorshipTransfer
|
||||
*
|
||||
* Type: ttSPONSORSHIP_TRANSFER (90)
|
||||
* Delegable: Delegation::NotDelegable
|
||||
* Amendment: featureSponsor
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use SponsorshipTransferBuilder to construct new transactions.
|
||||
*/
|
||||
class SponsorshipTransfer : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttSPONSORSHIP_TRANSFER;
|
||||
|
||||
/**
|
||||
* @brief Construct a SponsorshipTransfer transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit SponsorshipTransfer(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for SponsorshipTransfer");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfObjectID (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT256::type::value_type>
|
||||
getObjectID() const
|
||||
{
|
||||
if (hasObjectID())
|
||||
{
|
||||
return this->tx_->at(sfObjectID);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfObjectID is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasObjectID() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfObjectID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSponsee (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getSponsee() const
|
||||
{
|
||||
if (hasSponsee())
|
||||
{
|
||||
return this->tx_->at(sfSponsee);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSponsee is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSponsee() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfSponsee);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for SponsorshipTransfer transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class SponsorshipTransferBuilder : public TransactionBuilderBase<SponsorshipTransferBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new SponsorshipTransferBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
SponsorshipTransferBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<SponsorshipTransferBuilder>(ttSPONSORSHIP_TRANSFER, account, sequence, fee)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a SponsorshipTransferBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
SponsorshipTransferBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttSPONSORSHIP_TRANSFER)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for SponsorshipTransferBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfObjectID (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipTransferBuilder&
|
||||
setObjectID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfObjectID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSponsee (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SponsorshipTransferBuilder&
|
||||
setSponsee(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSponsee] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the SponsorshipTransfer wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
SponsorshipTransfer
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return SponsorshipTransfer{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,201 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainAccountCreateCommitBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainAccountCreateCommit
|
||||
*
|
||||
* Type: ttXCHAIN_ACCOUNT_CREATE_COMMIT (44)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainAccountCreateCommitBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainAccountCreateCommit : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_ACCOUNT_CREATE_COMMIT;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAccountCreateCommit transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainAccountCreateCommit(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAccountCreateCommit");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getDestination() const
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainAccountCreateCommit transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainAccountCreateCommitBuilder : public TransactionBuilderBase<XChainAccountCreateCommitBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainAccountCreateCommitBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainAccountCreateCommitBuilder>(ttXCHAIN_ACCOUNT_CREATE_COMMIT, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setDestination(destination);
|
||||
setAmount(amount);
|
||||
setSignatureReward(signatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAccountCreateCommitBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_ACCOUNT_CREATE_COMMIT)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAccountCreateCommitBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainAccountCreateCommit wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainAccountCreateCommit
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainAccountCreateCommit{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,369 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainAddAccountCreateAttestationBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainAddAccountCreateAttestation
|
||||
*
|
||||
* Type: ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION (46)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: CreateAcct
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainAddAccountCreateAttestationBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainAddAccountCreateAttestation : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddAccountCreateAttestation transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainAddAccountCreateAttestation(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAddAccountCreateAttestation");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationSignerAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationSignerAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationSignerAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPublicKey (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getPublicKey() const
|
||||
{
|
||||
return this->tx_->at(sfPublicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignature (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getSignature() const
|
||||
{
|
||||
return this->tx_->at(sfSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->tx_->at(sfOtherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationRewardAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationRewardAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationRewardAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfWasLockingChainSend (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT8::type::value_type
|
||||
getWasLockingChainSend() const
|
||||
{
|
||||
return this->tx_->at(sfWasLockingChainSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountCreateCount() const
|
||||
{
|
||||
return this->tx_->at(sfXChainAccountCreateCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getDestination() const
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainAddAccountCreateAttestation transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainAddAccountCreateAttestationBuilder : public TransactionBuilderBase<XChainAddAccountCreateAttestationBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainAddAccountCreateAttestationBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param attestationSignerAccount The sfAttestationSignerAccount field value.
|
||||
* @param publicKey The sfPublicKey field value.
|
||||
* @param signature The sfSignature field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param attestationRewardAccount The sfAttestationRewardAccount field value.
|
||||
* @param wasLockingChainSend The sfWasLockingChainSend field value.
|
||||
* @param xChainAccountCreateCount The sfXChainAccountCreateCount field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationSignerAccount, std::decay_t<typename SF_VL::type::value_type> const& publicKey, std::decay_t<typename SF_VL::type::value_type> const& signature, std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationRewardAccount, std::decay_t<typename SF_UINT8::type::value_type> const& wasLockingChainSend, std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountCreateCount, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainAddAccountCreateAttestationBuilder>(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setAttestationSignerAccount(attestationSignerAccount);
|
||||
setPublicKey(publicKey);
|
||||
setSignature(signature);
|
||||
setOtherChainSource(otherChainSource);
|
||||
setAmount(amount);
|
||||
setAttestationRewardAccount(attestationRewardAccount);
|
||||
setWasLockingChainSend(wasLockingChainSend);
|
||||
setXChainAccountCreateCount(xChainAccountCreateCount);
|
||||
setDestination(destination);
|
||||
setSignatureReward(signatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddAccountCreateAttestationBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAddAccountCreateAttestationBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationSignerAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setAttestationSignerAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationSignerAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPublicKey (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setPublicKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPublicKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignature (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setSignature(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignature] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationRewardAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setAttestationRewardAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationRewardAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfWasLockingChainSend (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setWasLockingChainSend(std::decay_t<typename SF_UINT8::type::value_type> const& value)
|
||||
{
|
||||
object_[sfWasLockingChainSend] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setXChainAccountCreateCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountCreateCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainAddAccountCreateAttestation wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainAddAccountCreateAttestation
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainAddAccountCreateAttestation{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,358 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainAddClaimAttestationBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainAddClaimAttestation
|
||||
*
|
||||
* Type: ttXCHAIN_ADD_CLAIM_ATTESTATION (45)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: CreateAcct
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainAddClaimAttestationBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainAddClaimAttestation : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_ADD_CLAIM_ATTESTATION;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddClaimAttestation transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainAddClaimAttestation(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAddClaimAttestation");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationSignerAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationSignerAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationSignerAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPublicKey (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getPublicKey() const
|
||||
{
|
||||
return this->tx_->at(sfPublicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignature (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getSignature() const
|
||||
{
|
||||
return this->tx_->at(sfSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->tx_->at(sfOtherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationRewardAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationRewardAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationRewardAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfWasLockingChainSend (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT8::type::value_type
|
||||
getWasLockingChainSend() const
|
||||
{
|
||||
return this->tx_->at(sfWasLockingChainSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->tx_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getDestination() const
|
||||
{
|
||||
if (hasDestination())
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDestination is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDestination() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestination);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainAddClaimAttestation transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainAddClaimAttestationBuilder : public TransactionBuilderBase<XChainAddClaimAttestationBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainAddClaimAttestationBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param attestationSignerAccount The sfAttestationSignerAccount field value.
|
||||
* @param publicKey The sfPublicKey field value.
|
||||
* @param signature The sfSignature field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param attestationRewardAccount The sfAttestationRewardAccount field value.
|
||||
* @param wasLockingChainSend The sfWasLockingChainSend field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationSignerAccount, std::decay_t<typename SF_VL::type::value_type> const& publicKey, std::decay_t<typename SF_VL::type::value_type> const& signature, std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationRewardAccount, std::decay_t<typename SF_UINT8::type::value_type> const& wasLockingChainSend, std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainAddClaimAttestationBuilder>(ttXCHAIN_ADD_CLAIM_ATTESTATION, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setAttestationSignerAccount(attestationSignerAccount);
|
||||
setPublicKey(publicKey);
|
||||
setSignature(signature);
|
||||
setOtherChainSource(otherChainSource);
|
||||
setAmount(amount);
|
||||
setAttestationRewardAccount(attestationRewardAccount);
|
||||
setWasLockingChainSend(wasLockingChainSend);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddClaimAttestationBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_ADD_CLAIM_ATTESTATION)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAddClaimAttestationBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationSignerAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setAttestationSignerAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationSignerAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPublicKey (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setPublicKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPublicKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignature (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setSignature(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignature] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationRewardAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setAttestationRewardAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationRewardAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfWasLockingChainSend (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setWasLockingChainSend(std::decay_t<typename SF_UINT8::type::value_type> const& value)
|
||||
{
|
||||
object_[sfWasLockingChainSend] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainAddClaimAttestation wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainAddClaimAttestation
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainAddClaimAttestation{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,238 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainClaimBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainClaim
|
||||
*
|
||||
* Type: ttXCHAIN_CLAIM (43)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainClaimBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainClaim : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_CLAIM;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainClaim transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainClaim(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainClaim");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->tx_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getDestination() const
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestinationTag (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getDestinationTag() const
|
||||
{
|
||||
if (hasDestinationTag())
|
||||
{
|
||||
return this->tx_->at(sfDestinationTag);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDestinationTag is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDestinationTag() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestinationTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainClaim transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainClaimBuilder : public TransactionBuilderBase<XChainClaimBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainClaimBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainClaimBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainClaimBuilder>(ttXCHAIN_CLAIM, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setDestination(destination);
|
||||
setAmount(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainClaimBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainClaimBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_CLAIM)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainClaimBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestinationTag (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestinationTag] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainClaim wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainClaim
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainClaim{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,214 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainCommitBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainCommit
|
||||
*
|
||||
* Type: ttXCHAIN_COMMIT (42)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainCommitBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainCommit : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_COMMIT;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCommit transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainCommit(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCommit");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->tx_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainDestination (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getOtherChainDestination() const
|
||||
{
|
||||
if (hasOtherChainDestination())
|
||||
{
|
||||
return this->tx_->at(sfOtherChainDestination);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfOtherChainDestination is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasOtherChainDestination() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfOtherChainDestination);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainCommit transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainCommitBuilder : public TransactionBuilderBase<XChainCommitBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainCommitBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainCommitBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainCommitBuilder>(ttXCHAIN_COMMIT, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setAmount(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCommitBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainCommitBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_COMMIT)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCommitBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainDestination (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setOtherChainDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainCommit wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainCommit
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainCommit{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,190 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainCreateBridgeBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainCreateBridge
|
||||
*
|
||||
* Type: ttXCHAIN_CREATE_BRIDGE (48)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainCreateBridgeBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainCreateBridge : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_CREATE_BRIDGE;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateBridge transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainCreateBridge(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCreateBridge");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMinAccountCreateAmount() const
|
||||
{
|
||||
if (hasMinAccountCreateAmount())
|
||||
{
|
||||
return this->tx_->at(sfMinAccountCreateAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMinAccountCreateAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMinAccountCreateAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMinAccountCreateAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainCreateBridge transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainCreateBridgeBuilder : public TransactionBuilderBase<XChainCreateBridgeBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainCreateBridgeBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainCreateBridgeBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainCreateBridgeBuilder>(ttXCHAIN_CREATE_BRIDGE, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setSignatureReward(signatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateBridgeBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainCreateBridgeBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_CREATE_BRIDGE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCreateBridgeBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateBridgeBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateBridgeBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateBridgeBuilder&
|
||||
setMinAccountCreateAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMinAccountCreateAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainCreateBridge wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainCreateBridge
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainCreateBridge{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,177 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainCreateClaimIDBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainCreateClaimID
|
||||
*
|
||||
* Type: ttXCHAIN_CREATE_CLAIM_ID (41)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainCreateClaimIDBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainCreateClaimID : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_CREATE_CLAIM_ID;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateClaimID transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainCreateClaimID(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCreateClaimID");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->tx_->at(sfOtherChainSource);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainCreateClaimID transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainCreateClaimIDBuilder : public TransactionBuilderBase<XChainCreateClaimIDBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainCreateClaimIDBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainCreateClaimIDBuilder>(ttXCHAIN_CREATE_CLAIM_ID, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setSignatureReward(signatureReward);
|
||||
setOtherChainSource(otherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateClaimIDBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_CREATE_CLAIM_ID)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCreateClaimIDBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainCreateClaimID wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainCreateClaimID
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainCreateClaimID{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,203 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class XChainModifyBridgeBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainModifyBridge
|
||||
*
|
||||
* Type: ttXCHAIN_MODIFY_BRIDGE (47)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainModifyBridgeBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainModifyBridge : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_MODIFY_BRIDGE;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainModifyBridge transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainModifyBridge(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainModifyBridge");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getSignatureReward() const
|
||||
{
|
||||
if (hasSignatureReward())
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSignatureReward is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSignatureReward() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMinAccountCreateAmount() const
|
||||
{
|
||||
if (hasMinAccountCreateAmount())
|
||||
{
|
||||
return this->tx_->at(sfMinAccountCreateAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMinAccountCreateAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMinAccountCreateAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMinAccountCreateAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainModifyBridge transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class XChainModifyBridgeBuilder : public TransactionBuilderBase<XChainModifyBridgeBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainModifyBridgeBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainModifyBridgeBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainModifyBridgeBuilder>(ttXCHAIN_MODIFY_BRIDGE, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainModifyBridgeBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainModifyBridgeBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_MODIFY_BRIDGE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainModifyBridgeBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainModifyBridgeBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainModifyBridgeBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainModifyBridgeBuilder&
|
||||
setMinAccountCreateAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMinAccountCreateAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainModifyBridge wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainModifyBridge
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainModifyBridge{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -127,6 +127,15 @@ public:
|
||||
TER
|
||||
checkInvariants(TER const result, XRPAmount const fee);
|
||||
|
||||
ApplyViewContext
|
||||
getApplyViewContext()
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
view_.has_value(),
|
||||
"xrpl::ApplyContext::getApplyViewContext : view_ emplaced in constructor");
|
||||
return {.view = *view_, .tx = tx};
|
||||
}
|
||||
|
||||
private:
|
||||
static TER
|
||||
failInvariantCheck(TER const result);
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/Permissions.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
@@ -126,6 +128,21 @@ struct PreflightResult;
|
||||
// Needed for preflight specialization
|
||||
class Change;
|
||||
|
||||
enum class FeePayerType {
|
||||
Account,
|
||||
Delegate,
|
||||
SponsorCoSigned,
|
||||
SponsorPreFunded,
|
||||
};
|
||||
|
||||
struct FeePayer
|
||||
{
|
||||
AccountID id;
|
||||
Keylet keylet;
|
||||
SF_AMOUNT const& balanceField;
|
||||
FeePayerType type{FeePayerType::Account};
|
||||
};
|
||||
|
||||
class Transactor
|
||||
{
|
||||
protected:
|
||||
@@ -298,6 +315,10 @@ public:
|
||||
|
||||
return T::checkGranularSemantics(view, tx, heldGranularPermissions);
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
checkSponsor(ReadView const& view, STTx const& tx);
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
// Interface used by AccountDelete
|
||||
@@ -459,6 +480,9 @@ private:
|
||||
std::pair<TER, XRPAmount>
|
||||
reset(XRPAmount fee);
|
||||
|
||||
static FeePayer
|
||||
getFeePayer(ReadView const& view, STTx const& tx);
|
||||
|
||||
TER
|
||||
consumeSeqProxy(SLE::pointer const& sleAccount);
|
||||
TER
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <xrpl/tx/invariants/NFTInvariant.h>
|
||||
#include <xrpl/tx/invariants/PermissionedDEXInvariant.h>
|
||||
#include <xrpl/tx/invariants/PermissionedDomainInvariant.h>
|
||||
#include <xrpl/tx/invariants/SponsorshipInvariant.h>
|
||||
#include <xrpl/tx/invariants/VaultInvariant.h>
|
||||
|
||||
#include <cstdint>
|
||||
@@ -441,7 +442,9 @@ using InvariantChecks = std::tuple<
|
||||
ValidMPTPayment,
|
||||
ValidAmounts,
|
||||
ValidMPTTransfer,
|
||||
ObjectHasPseudoAccount>;
|
||||
ObjectHasPseudoAccount,
|
||||
SponsorshipOwnerCountsMatch,
|
||||
SponsorshipAccountCountMatchesField>;
|
||||
|
||||
/**
|
||||
* @brief get a tuple of all invariant checks
|
||||
|
||||
61
include/xrpl/tx/invariants/SponsorshipInvariant.h
Normal file
61
include/xrpl/tx/invariants/SponsorshipInvariant.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Invariant: Sponsored owner counts are balanced.
|
||||
*
|
||||
* The following checks are made for every transaction:
|
||||
* - The sum of all per-account deltas of `sfSponsoredOwnerCount` equals
|
||||
* the sum of all per-account deltas of `sfSponsoringOwnerCount`.
|
||||
* - Account OwnerCount must be greater than or equal to SponsoredOwnerCount.
|
||||
* - The net delta of sponsored object owner counts (the owner-count
|
||||
* magnitude of sponsored ledger entries) equals the net delta of
|
||||
* `sfSponsoredOwnerCount`.
|
||||
*/
|
||||
class SponsorshipOwnerCountsMatch
|
||||
{
|
||||
std::int64_t deltaSponsoredOwnerCount_ = 0;
|
||||
std::int64_t deltaSponsoringOwnerCount_ = 0;
|
||||
std::int64_t deltaSponsoredObjectOwnerCount_ = 0;
|
||||
std::uint64_t ownerCountBelowSponsored_ = 0;
|
||||
|
||||
public:
|
||||
void
|
||||
visitEntry(bool, SLE::const_ref, SLE::const_ref);
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Invariant: Sponsoring account relationships tracked consistently.
|
||||
*
|
||||
* The following check is made for every transaction:
|
||||
* - The net delta of `sfSponsoringAccountCount` across all accounts equals
|
||||
* the net delta of the count of ltACCOUNT_ROOT entries having
|
||||
* `sfSponsor` present (presence transitions only: add/remove).
|
||||
*/
|
||||
class SponsorshipAccountCountMatchesField
|
||||
{
|
||||
std::int64_t deltaSponsoringAccountCount_ = 0;
|
||||
std::int64_t deltaSponsorFieldPresence_ = 0;
|
||||
|
||||
public:
|
||||
void
|
||||
visitEntry(bool, SLE::const_ref, SLE::const_ref);
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Concepts.h>
|
||||
#include <xrpl/protocol/Quality.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <cstdint>
|
||||
@@ -110,7 +111,10 @@ public:
|
||||
send(Args&&... args)
|
||||
{
|
||||
return accountSend(
|
||||
std::forward<Args>(args)..., WaiveTransferFee::Yes, AllowMPTOverflow::Yes);
|
||||
std::forward<Args>(args)...,
|
||||
SLE::pointer(),
|
||||
WaiveTransferFee::Yes,
|
||||
AllowMPTOverflow::Yes);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
|
||||
@@ -234,7 +234,8 @@ template <typename... Args>
|
||||
TER
|
||||
TOffer<TIn, TOut>::send(Args&&... args)
|
||||
{
|
||||
return accountSend(std::forward<Args>(args)..., WaiveTransferFee::No, AllowMPTOverflow::Yes);
|
||||
return accountSend(
|
||||
std::forward<Args>(args)..., SLE::pointer(), WaiveTransferFee::No, AllowMPTOverflow::Yes);
|
||||
}
|
||||
|
||||
template <StepAmount TIn, StepAmount TOut>
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
constexpr size_t kXbridgeMaxAccountCreateClaims = 128;
|
||||
|
||||
// Attach a new bridge to a door account. Once this is done, the cross-chain
|
||||
// transfer transactions may be used to transfer funds from this account.
|
||||
class XChainCreateBridge : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit XChainCreateBridge(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
class BridgeModify : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit BridgeModify(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
using XChainModifyBridge = BridgeModify;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Claim funds from a `XChainCommit` transaction. This is normally not needed,
|
||||
// but may be used to handle transaction failures or if the destination account
|
||||
// was not specified in the `XChainCommit` transaction. It may only be used
|
||||
// after a quorum of signatures have been sent from the witness servers.
|
||||
//
|
||||
// If the transaction succeeds in moving funds, the referenced `XChainClaimID`
|
||||
// ledger object will be destroyed. This prevents transaction replay. If the
|
||||
// transaction fails, the `XChainClaimID` will not be destroyed and the
|
||||
// transaction may be re-run with different parameters.
|
||||
class XChainClaim : public Transactor
|
||||
{
|
||||
public:
|
||||
// Blocker since we cannot accurately calculate the consequences
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker;
|
||||
|
||||
explicit XChainClaim(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Put assets into trust on the locking-chain so they may be wrapped on the
|
||||
// issuing-chain, or return wrapped assets on the issuing-chain so they can be
|
||||
// unlocked on the locking-chain. The second step in a cross-chain transfer.
|
||||
class XChainCommit : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Custom;
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
explicit XChainCommit(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Create a new claim id owned by the account. This is the first step in a
|
||||
// cross-chain transfer. The claim id must be created on the destination chain
|
||||
// before the `XChainCommit` transaction (which must reference this number) can
|
||||
// be sent on the source chain. The account that will send the `XChainCommit` on
|
||||
// the source chain must be specified in this transaction (see note on the
|
||||
// `SourceAccount` field in the `XChainClaimID` ledger object for
|
||||
// justification). The actual sequence number must be retrieved from a validated
|
||||
// ledger.
|
||||
class XChainCreateClaimID : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit XChainCreateClaimID(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Provide attestations from a witness server attesting to events on
|
||||
// the other chain. The signatures must be from one of the keys on the door's
|
||||
// signer's list at the time the signature was provided. However, if the
|
||||
// signature list changes between the time the signature was submitted and the
|
||||
// quorum is reached, the new signature set is used and some of the currently
|
||||
// collected signatures may be removed. Also note the reward is only sent to
|
||||
// accounts that have keys on the current list.
|
||||
class XChainAddClaimAttestation : public Transactor
|
||||
{
|
||||
public:
|
||||
// Blocker since we cannot accurately calculate the consequences
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker;
|
||||
|
||||
explicit XChainAddClaimAttestation(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
class XChainAddAccountCreateAttestation : public Transactor
|
||||
{
|
||||
public:
|
||||
// Blocker since we cannot accurately calculate the consequences
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker;
|
||||
|
||||
explicit XChainAddAccountCreateAttestation(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// This is a special transaction used for creating accounts through a
|
||||
// cross-chain transfer. A normal cross-chain transfer requires a "chain claim
|
||||
// id" (which requires an existing account on the destination chain). One
|
||||
// purpose of the "chain claim id" is to prevent transaction replay. For this
|
||||
// transaction, we use a different mechanism: the accounts must be claimed on
|
||||
// the destination chain in the same order that the `XChainCreateAccountCommit`
|
||||
// transactions occurred on the source chain.
|
||||
//
|
||||
// This transaction can only be used for XRP to XRP bridges.
|
||||
//
|
||||
// IMPORTANT: This transaction should only be enabled if the witness
|
||||
// attestations will be reliably delivered to the destination chain. If the
|
||||
// signatures are not delivered (for example, the chain relies on user wallets
|
||||
// to collect signatures) then account creation would be blocked for all
|
||||
// transactions that happened after the one waiting on attestations. This could
|
||||
// be used maliciously. To disable this transaction on XRP to XRP bridges, the
|
||||
// bridge's `MinAccountCreateAmount` should not be present.
|
||||
//
|
||||
// Note: If this account already exists, the XRP is transferred to the existing
|
||||
// account. However, note that unlike the `XChainCommit` transaction, there is
|
||||
// no error handling mechanism. If the claim transaction fails, there is no
|
||||
// mechanism for refunds. The funds are permanently lost. This transaction
|
||||
// should still only be used for account creation.
|
||||
class XChainCreateAccountCommit : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit XChainCreateAccountCommit(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
using XChainAccountCreateCommit = XChainCreateAccountCommit;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // namespace xrpl
|
||||
52
include/xrpl/tx/transactors/sponsor/SponsorshipSet.h
Normal file
52
include/xrpl/tx/transactors/sponsor/SponsorshipSet.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class SponsorshipSet : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit SponsorshipSet(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
49
include/xrpl/tx/transactors/sponsor/SponsorshipTransfer.h
Normal file
49
include/xrpl/tx/transactors/sponsor/SponsorshipTransfer.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class SponsorshipTransfer : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit SponsorshipTransfer(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
beast::Journal const& j) override;
|
||||
|
||||
static std::expected<MPTID, TER>
|
||||
create(ApplyView& view, beast::Journal journal, MPTCreateArgs const& args);
|
||||
create(ApplyViewContext ctx, beast::Journal journal, MPTCreateArgs const& args);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -4,14 +4,16 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs; }) commonPackages;
|
||||
inherit (pkgs) lib;
|
||||
inherit (import ./packages.nix { inherit pkgs; })
|
||||
commonPackages
|
||||
gccPackage
|
||||
llvmPackages
|
||||
llvmVersion
|
||||
;
|
||||
|
||||
# Underlying compiler toolchains to wrap. Bump these in one place to
|
||||
# roll the whole environment forward.
|
||||
customGccPackage = pkgs.gcc15;
|
||||
customLlvmPackages = pkgs.llvmPackages_22;
|
||||
customClangMajor = lib.versions.major (lib.getVersion customLlvmPackages.clang-unwrapped);
|
||||
# Underlying compiler toolchains to wrap (versions pinned in packages.nix).
|
||||
customGccPackage = gccPackage;
|
||||
customLlvmPackages = llvmPackages;
|
||||
|
||||
# binutils wrapped to emit binaries that reference the custom glibc
|
||||
# (dynamic linker path, library search path, RPATH).
|
||||
@@ -90,7 +92,7 @@ let
|
||||
extraBuildCommands = ''
|
||||
rsrc="$out/resource-root"
|
||||
mkdir "$rsrc"
|
||||
ln -s "${customLlvmPackages.clang-unwrapped.lib}/lib/clang/${customClangMajor}/include" "$rsrc/include"
|
||||
ln -s "${customLlvmPackages.clang-unwrapped.lib}/lib/clang/${toString llvmVersion}/include" "$rsrc/include"
|
||||
ln -s "${customCompilerRt.out}/lib" "$rsrc/lib"
|
||||
ln -s "${customCompilerRt.out}/share" "$rsrc/share" || true
|
||||
echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
|
||||
|
||||
150
nix/devshell.nix
150
nix/devshell.nix
@@ -1,127 +1,57 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs; }) commonPackages;
|
||||
inherit (import ./packages.nix { inherit pkgs; })
|
||||
commonPackages
|
||||
gccVersion
|
||||
llvmPackages
|
||||
;
|
||||
|
||||
# Supported compiler versions
|
||||
gccVersion = pkgs.lib.range 13 15;
|
||||
clangVersions = pkgs.lib.range 18 21;
|
||||
# Plain nixpkgs stdenvs — no custom glibc, unlike ci-env.nix.
|
||||
gccStdenv = pkgs."gcc${toString gccVersion}Stdenv";
|
||||
clangStdenv = llvmPackages.stdenv;
|
||||
|
||||
defaultCompiler = if pkgs.stdenv.isDarwin then "apple-clang" else "gcc";
|
||||
defaultGccVersion = pkgs.lib.last gccVersion;
|
||||
defaultClangVersion = pkgs.lib.last clangVersions;
|
||||
|
||||
strToCompilerEnv =
|
||||
compiler: version:
|
||||
(
|
||||
if compiler == "gcc" then
|
||||
let
|
||||
gccPkg = pkgs."gcc${toString version}Stdenv" or null;
|
||||
in
|
||||
if gccPkg != null && builtins.elem version gccVersion then
|
||||
gccPkg
|
||||
else
|
||||
throw "Invalid GCC version: ${toString version}. Must be one of: ${toString gccVersion}"
|
||||
else if compiler == "clang" then
|
||||
let
|
||||
clangPkg = pkgs."llvmPackages_${toString version}".stdenv or null;
|
||||
in
|
||||
if clangPkg != null && builtins.elem version clangVersions then
|
||||
clangPkg
|
||||
else
|
||||
throw "Invalid Clang version: ${toString version}. Must be one of: ${toString clangVersions}"
|
||||
else if compiler == "apple-clang" || compiler == "none" then
|
||||
pkgs.stdenvNoCC
|
||||
else
|
||||
throw "Invalid compiler: ${compiler}. Must be one of: gcc, clang, apple-clang, none"
|
||||
);
|
||||
|
||||
# Helper function to create a shell with a specific compiler
|
||||
# compilerName is the command used to print the version, or null for none.
|
||||
makeShell =
|
||||
{
|
||||
compiler ? defaultCompiler,
|
||||
version ? (
|
||||
if compiler == "gcc" then
|
||||
defaultGccVersion
|
||||
else if compiler == "clang" then
|
||||
defaultClangVersion
|
||||
else
|
||||
null
|
||||
),
|
||||
stdenv,
|
||||
compilerName,
|
||||
}:
|
||||
let
|
||||
compilerStdEnv = strToCompilerEnv compiler version;
|
||||
|
||||
compilerName =
|
||||
if compiler == "apple-clang" then
|
||||
"clang"
|
||||
else if compiler == "none" then
|
||||
null
|
||||
else
|
||||
compiler;
|
||||
|
||||
gccOnMacWarning =
|
||||
if pkgs.stdenv.isDarwin && compiler == "gcc" then
|
||||
''
|
||||
echo "WARNING: Using GCC on macOS with Conan may not work."
|
||||
echo " Consider using 'nix develop .#clang' or the default shell instead."
|
||||
echo ""
|
||||
''
|
||||
else
|
||||
"";
|
||||
|
||||
compilerVersion =
|
||||
if compilerName != null then
|
||||
if compilerName == null then
|
||||
''echo "No compiler specified - using system compiler"''
|
||||
else
|
||||
''
|
||||
echo "Compiler: "
|
||||
${compilerName} --version
|
||||
''
|
||||
else
|
||||
''
|
||||
echo "No compiler specified - using system compiler"
|
||||
'';
|
||||
|
||||
shellAttrs = {
|
||||
packages = commonPackages;
|
||||
|
||||
shellHook = ''
|
||||
echo "Welcome to xrpld development shell";
|
||||
${gccOnMacWarning}${compilerVersion}
|
||||
'';
|
||||
};
|
||||
in
|
||||
pkgs.mkShell.override { stdenv = compilerStdEnv; } shellAttrs;
|
||||
|
||||
# Generate shells for each compiler version
|
||||
gccShells = builtins.listToAttrs (
|
||||
map (version: {
|
||||
name = "gcc${toString version}";
|
||||
value = makeShell {
|
||||
compiler = "gcc";
|
||||
version = version;
|
||||
};
|
||||
}) gccVersion
|
||||
);
|
||||
|
||||
clangShells = builtins.listToAttrs (
|
||||
map (version: {
|
||||
name = "clang${toString version}";
|
||||
value = makeShell {
|
||||
compiler = "clang";
|
||||
version = version;
|
||||
};
|
||||
}) clangVersions
|
||||
);
|
||||
|
||||
(pkgs.mkShell.override { inherit stdenv; }) {
|
||||
packages = commonPackages;
|
||||
shellHook = ''
|
||||
echo "Welcome to xrpld development shell";
|
||||
${compilerVersion}
|
||||
'';
|
||||
};
|
||||
in
|
||||
gccShells
|
||||
// clangShells
|
||||
// {
|
||||
# Default shells
|
||||
default = makeShell { };
|
||||
gcc = makeShell { compiler = "gcc"; };
|
||||
clang = makeShell { compiler = "clang"; };
|
||||
rec {
|
||||
# macOS: Nix Clang. Linux: Nix GCC.
|
||||
default = if pkgs.stdenv.isDarwin then clang else gcc;
|
||||
|
||||
# No compiler
|
||||
no-compiler = makeShell { compiler = "none"; };
|
||||
apple-clang = makeShell { compiler = "apple-clang"; };
|
||||
gcc = makeShell {
|
||||
stdenv = gccStdenv;
|
||||
compilerName = "gcc";
|
||||
};
|
||||
|
||||
clang = makeShell {
|
||||
stdenv = clangStdenv;
|
||||
compilerName = "clang";
|
||||
};
|
||||
|
||||
# Nix provides no compiler; use the one from your system (e.g. Apple Clang).
|
||||
no-compiler = makeShell {
|
||||
stdenv = pkgs.stdenvNoCC;
|
||||
compilerName = null;
|
||||
};
|
||||
apple-clang = no-compiler;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,33 @@
|
||||
{ pkgs }:
|
||||
let
|
||||
# Compiler versions used across the dev shell and the CI environment.
|
||||
gccVersion = 15;
|
||||
llvmVersion = 22;
|
||||
|
||||
gccPackage = pkgs."gcc${toString gccVersion}";
|
||||
llvmPackages = pkgs."llvmPackages_${toString llvmVersion}";
|
||||
|
||||
# Bound explicitly so it tracks llvmPackages above, not the `with pkgs` default.
|
||||
clangTools = llvmPackages.clang-tools;
|
||||
|
||||
# In LLVM 22, run-clang-tidy.py moved from share/clang/ to bin/, so nixpkgs
|
||||
# clang-tools no longer links it. Wrap it manually.
|
||||
runClangTidy = pkgs.writeShellScriptBin "run-clang-tidy" ''
|
||||
exec ${pkgs.python3}/bin/python3 ${pkgs.llvmPackages_22.clang-unwrapped}/bin/run-clang-tidy "$@"
|
||||
exec ${pkgs.python3}/bin/python3 ${llvmPackages.clang-unwrapped}/bin/run-clang-tidy "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
inherit
|
||||
gccVersion
|
||||
llvmVersion
|
||||
gccPackage
|
||||
llvmPackages
|
||||
;
|
||||
|
||||
commonPackages = with pkgs; [
|
||||
ccache
|
||||
clangbuildanalyzer
|
||||
clangTools
|
||||
cmake
|
||||
conan
|
||||
curlMinimal # needed for codecov/codecov-action
|
||||
@@ -23,7 +41,6 @@ in
|
||||
gnumake
|
||||
gnupg # needed for signing commits & codecov/codecov-action
|
||||
graphviz
|
||||
llvmPackages_22.clang-tools
|
||||
less # needed for git diff
|
||||
mold
|
||||
nettools # provides netstat, used to debug failures in CI
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/RawView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -170,7 +171,7 @@ DeferredCredits::issuerSelfDebitMPT(
|
||||
}
|
||||
|
||||
void
|
||||
DeferredCredits::ownerCount(AccountID const& id, std::uint32_t cur, std::uint32_t next)
|
||||
DeferredCredits::ownerCount(AccountID const& id, OwnerCounts const& cur, OwnerCounts const& next)
|
||||
{
|
||||
auto const v = std::max(cur, next);
|
||||
auto r = ownerCounts_.emplace(id, v);
|
||||
@@ -181,7 +182,7 @@ DeferredCredits::ownerCount(AccountID const& id, std::uint32_t cur, std::uint32_
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t>
|
||||
std::optional<OwnerCounts>
|
||||
DeferredCredits::ownerCount(AccountID const& id) const
|
||||
{
|
||||
auto i = ownerCounts_.find(id);
|
||||
@@ -391,10 +392,10 @@ PaymentSandbox::balanceHookSelfIssueMPT(xrpl::MPTIssue const& issue, std::int64_
|
||||
return STAmount{issue};
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
PaymentSandbox::ownerCountHook(AccountID const& account, std::uint32_t count) const
|
||||
OwnerCounts
|
||||
PaymentSandbox::ownerCountHook(AccountID const& account, OwnerCounts const& count) const
|
||||
{
|
||||
std::uint32_t result = count;
|
||||
OwnerCounts result = count;
|
||||
for (auto curSB = this; curSB != nullptr; curSB = curSB->ps_)
|
||||
{
|
||||
if (auto adj = curSB->tab_.ownerCount(account))
|
||||
@@ -442,8 +443,8 @@ PaymentSandbox::issuerSelfDebitHookMPT(
|
||||
void
|
||||
PaymentSandbox::adjustOwnerCountHook(
|
||||
AccountID const& account,
|
||||
std::uint32_t cur,
|
||||
std::uint32_t next)
|
||||
OwnerCounts const& cur,
|
||||
OwnerCounts const& next)
|
||||
{
|
||||
tab_.ownerCount(account, cur, next);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
@@ -431,8 +432,7 @@ canWithdraw(ReadView const& view, STTx const& tx)
|
||||
|
||||
TER
|
||||
doWithdraw(
|
||||
ApplyView& view,
|
||||
STTx const& tx,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& senderAcct,
|
||||
AccountID const& dstAcct,
|
||||
AccountID const& sourceAcct,
|
||||
@@ -440,23 +440,24 @@ doWithdraw(
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
auto const dstSle = ctx.view.read(keylet::account(dstAcct));
|
||||
|
||||
// Create trust line or MPToken for the receiving account
|
||||
if (dstAcct == senderAcct)
|
||||
{
|
||||
if (auto const ter = addEmptyHolding(view, senderAcct, priorBalance, amount.asset(), j);
|
||||
if (auto const ter = addEmptyHolding(ctx, senderAcct, priorBalance, amount.asset(), j);
|
||||
!isTesSuccess(ter) && ter != tecDUPLICATE)
|
||||
return ter;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dstSle = view.read(keylet::account(dstAcct));
|
||||
if (auto err = verifyDepositPreauth(tx, view, senderAcct, dstAcct, dstSle, j))
|
||||
if (auto err = verifyDepositPreauth(ctx.tx, ctx.view, senderAcct, dstAcct, dstSle, j))
|
||||
return err;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (accountHolds(
|
||||
view,
|
||||
ctx.view,
|
||||
sourceAcct,
|
||||
amount.asset(),
|
||||
FreezeHandling::IgnoreFreeze,
|
||||
@@ -469,9 +470,18 @@ doWithdraw(
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
// A reserve sponsor only covers tx.Account's own objects, so resolve the
|
||||
// sponsor against the destination. accountSend can auto-create a holding
|
||||
// for dstAcct; keying on the destination ensures a third-party destination's
|
||||
// holding is never stamped with the tx's reserve sponsor.
|
||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, dstSle);
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
// Move the funds directly from the broker's pseudo-account to the
|
||||
// dstAcct
|
||||
return accountSend(view, sourceAcct, dstAcct, amount, j, WaiveTransferFee::Yes);
|
||||
return accountSend(
|
||||
ctx.view, sourceAcct, dstAcct, amount, j, *sponsorSle, WaiveTransferFee::Yes);
|
||||
}
|
||||
|
||||
TER
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/OwnerCounts.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -15,6 +17,7 @@
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
@@ -41,46 +44,226 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer)
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// An owner count cannot be negative. If adjustment would cause a negative
|
||||
// owner count, clamp the owner count at 0. Similarly for overflow. This
|
||||
// adjustment allows the ownerCount to be adjusted up or down in multiple steps.
|
||||
// If id != std::nullopt, then do error reporting.
|
||||
//
|
||||
// Returns adjusted owner count.
|
||||
static std::uint32_t
|
||||
std::uint32_t
|
||||
confineOwnerCount(
|
||||
std::uint32_t current,
|
||||
std::int32_t adjustment,
|
||||
std::uint32_t currentOwnerCount,
|
||||
std::int32_t ownerCountAdj,
|
||||
std::optional<AccountID> const& id = std::nullopt,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
{
|
||||
std::uint32_t adjusted{current + adjustment};
|
||||
if (adjustment > 0)
|
||||
std::uint32_t totalOwnerCount{currentOwnerCount + ownerCountAdj};
|
||||
if (ownerCountAdj > 0)
|
||||
{
|
||||
// Overflow is well defined on unsigned
|
||||
if (adjusted < current)
|
||||
if (totalOwnerCount < currentOwnerCount)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
if (id)
|
||||
{
|
||||
JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!";
|
||||
}
|
||||
adjusted = std::numeric_limits<std::uint32_t>::max();
|
||||
totalOwnerCount = std::numeric_limits<std::uint32_t>::max();
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Underflow is well defined on unsigned
|
||||
if (adjusted > current)
|
||||
if (totalOwnerCount > currentOwnerCount)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
if (id)
|
||||
{
|
||||
JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!";
|
||||
}
|
||||
adjusted = 0;
|
||||
totalOwnerCount = 0;
|
||||
XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
return adjusted;
|
||||
return totalOwnerCount;
|
||||
}
|
||||
|
||||
// Returns the number of account reserves funded by this account: 1 for itself (0 if sponsored by
|
||||
// another account) plus the count of accounts it sponsors.
|
||||
std::uint32_t
|
||||
accountCountImpl(SLE::const_ref sle, std::int32_t accountCountAdj, beast::Journal j)
|
||||
{
|
||||
bool const isSponsored = sle->isFieldPresent(sfSponsor);
|
||||
std::int64_t const sponsoringAccountCount = sle->getFieldU32(sfSponsoringAccountCount);
|
||||
std::int64_t const currentAccountCount = (isSponsored ? 0 : 1) + sponsoringAccountCount;
|
||||
|
||||
std::int64_t totalAccountCount{currentAccountCount + accountCountAdj};
|
||||
if (totalAccountCount > std::numeric_limits<std::uint32_t>::max())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Reserve count exceeds max!";
|
||||
totalAccountCount = std::numeric_limits<std::uint32_t>::max();
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
else if (totalAccountCount < 0)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::accountCountImpl : Reserve count set below 0");
|
||||
JLOG(j.fatal()) << "Reserve count set below 0";
|
||||
totalAccountCount = 0;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return totalAccountCount;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
adjustOwnerCountImpl(
|
||||
ApplyView& view,
|
||||
SLE::ref sle,
|
||||
SF_UINT32 const& sfield,
|
||||
AccountID const& accID,
|
||||
std::int32_t ownerCountAdj,
|
||||
beast::Journal j)
|
||||
{
|
||||
std::uint32_t const currentOwnerCount = sle->at(sfield);
|
||||
std::uint32_t const totalOwnerCount =
|
||||
confineOwnerCount(currentOwnerCount, ownerCountAdj, accID, j);
|
||||
sle->at(sfield) = totalOwnerCount;
|
||||
view.update(sle);
|
||||
return totalOwnerCount;
|
||||
}
|
||||
|
||||
void
|
||||
adjustOwnerCountSigned(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::int32_t adjustment,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (view.rules().enabled(featureSponsor))
|
||||
{
|
||||
XRPL_ASSERT(accountSle, "xrpl::adjustOwnerCountSigned : valid account sle");
|
||||
if (!accountSle)
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
auto const accountID = accountSle->getAccountID(sfAccount);
|
||||
bool const validType = accountSle->getType() == ltACCOUNT_ROOT;
|
||||
XRPL_ASSERT(validType, "xrpl::adjustOwnerCountSigned : valid account sle type");
|
||||
if (!validType)
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCountSigned : nonzero adjustment input");
|
||||
|
||||
OwnerCounts const currentOwnerCount(accountSle);
|
||||
OwnerCounts totalOwnerCount(currentOwnerCount);
|
||||
|
||||
if (sponsorSle)
|
||||
{
|
||||
bool const validSponsorType = sponsorSle->getType() == ltACCOUNT_ROOT;
|
||||
XRPL_ASSERT(validSponsorType, "xrpl::adjustOwnerCountSigned : valid sponsor sle type");
|
||||
if (!validSponsorType)
|
||||
return; // LCOV_EXCL_LINE
|
||||
auto const sponsorID = sponsorSle->getAccountID(sfAccount);
|
||||
|
||||
totalOwnerCount.sponsored = adjustOwnerCountImpl(
|
||||
view, accountSle, sfSponsoredOwnerCount, accountID, adjustment, j);
|
||||
|
||||
{
|
||||
OwnerCounts const sponsorCurrent(sponsorSle);
|
||||
OwnerCounts sponsorAdjustment(sponsorCurrent);
|
||||
sponsorAdjustment.sponsoring = adjustOwnerCountImpl(
|
||||
view, sponsorSle, sfSponsoringOwnerCount, sponsorID, adjustment, j);
|
||||
view.adjustOwnerCountHook(sponsorID, sponsorCurrent, sponsorAdjustment);
|
||||
}
|
||||
|
||||
auto sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
|
||||
if (sponsorshipSle && adjustment > 0)
|
||||
{
|
||||
// Only decrease the pre-funded ReserveCount on Sponsorship if we assign new
|
||||
// objects. Removing/reassigning ownership of the object doesn't increase
|
||||
// RemainingOwnerCount back. Don't call hook because this counter is not something
|
||||
// that requires reserve (like other sf...OwnerCounts do).
|
||||
adjustOwnerCountImpl(
|
||||
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j);
|
||||
}
|
||||
}
|
||||
|
||||
totalOwnerCount.owner =
|
||||
adjustOwnerCountImpl(view, accountSle, sfOwnerCount, accountID, adjustment, j);
|
||||
view.adjustOwnerCountHook(accountID, currentOwnerCount, totalOwnerCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
XRPL_ASSERT(accountSle, "xrpl::adjustOwnerCountSigned : valid account sle");
|
||||
if (!accountSle)
|
||||
return;
|
||||
// the remaining are only asserts to preserve existing behavior
|
||||
XRPL_ASSERT(sponsorSle == nullptr, "xrpl::adjustOwnerCountSigned : sponsor not enabled");
|
||||
XRPL_ASSERT(
|
||||
accountSle->getType() == ltACCOUNT_ROOT,
|
||||
"xrpl::adjustOwnerCountSigned : valid account sle type");
|
||||
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCount : nonzero adjustment input");
|
||||
std::uint32_t const current{accountSle->getFieldU32(sfOwnerCount)};
|
||||
AccountID const id = (*accountSle)[sfAccount];
|
||||
std::uint32_t const adjusted = confineOwnerCount(current, adjustment, id, j);
|
||||
|
||||
OwnerCounts const currentOwnerCount(accountSle);
|
||||
OwnerCounts finalOwnerCount(currentOwnerCount);
|
||||
finalOwnerCount.owner = adjusted;
|
||||
|
||||
view.adjustOwnerCountHook(id, currentOwnerCount, finalOwnerCount);
|
||||
accountSle->at(sfOwnerCount) = adjusted;
|
||||
view.update(accountSle);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::uint32_t
|
||||
ownerCount(SLE::const_ref sle, beast::Journal j, std::int32_t ownerCountAdj)
|
||||
{
|
||||
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::ownerCount : sle is account root");
|
||||
|
||||
AccountID const id = sle->getAccountID(sfAccount);
|
||||
std::uint32_t const currentOwnerCount = sle->at(sfOwnerCount);
|
||||
std::uint32_t const sponsoredOwnerCount = sle->at(sfSponsoredOwnerCount);
|
||||
std::uint32_t const sponsoringOwnerCount = sle->at(sfSponsoringOwnerCount);
|
||||
|
||||
XRPL_ASSERT(
|
||||
currentOwnerCount >= sponsoredOwnerCount,
|
||||
"xrpl::ownerCount : OwnerCount must be greater than or equal to SponsoredOwnerCount");
|
||||
|
||||
std::int64_t deltaCount =
|
||||
static_cast<std::int64_t>(ownerCountAdj) - sponsoredOwnerCount + sponsoringOwnerCount;
|
||||
|
||||
if (deltaCount > std::numeric_limits<std::int32_t>::max())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
deltaCount = std::numeric_limits<std::int32_t>::max();
|
||||
JLOG(j.fatal()) << "Account " << id << " delta count exceeds max, "
|
||||
<< "adjustment: " << ownerCountAdj
|
||||
<< ", sponsoredCount: " << sponsoredOwnerCount
|
||||
<< ", sponsoringOwnerCount: " << sponsoringOwnerCount;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
else if (deltaCount < std::numeric_limits<std::int32_t>::min())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
deltaCount = std::numeric_limits<std::int32_t>::min();
|
||||
JLOG(j.fatal()) << "Account " << id << " delta count is below min, "
|
||||
<< "adjustment: " << ownerCountAdj
|
||||
<< ", sponsoredCount: " << sponsoredOwnerCount
|
||||
<< ", sponsoringCount: " << sponsoringOwnerCount;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return confineOwnerCount(currentOwnerCount, deltaCount);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
@@ -91,12 +274,14 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
|
||||
return beast::kZero;
|
||||
|
||||
// Return balance minus reserve
|
||||
std::uint32_t const ownerCount =
|
||||
confineOwnerCount(view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
|
||||
std::uint32_t const currentOwnerCount =
|
||||
confineOwnerCount(view.ownerCountHook(id, OwnerCounts(sle)).count(), ownerCountAdj);
|
||||
std::uint32_t const currentAccountCount = accountCountImpl(sle, 0, j);
|
||||
|
||||
// Pseudo-accounts have no reserve requirement
|
||||
auto const reserve =
|
||||
isPseudoAccount(sle) ? XRPAmount{0} : view.fees().accountReserve(ownerCount);
|
||||
auto const reserve = isPseudoAccount(sle)
|
||||
? XRPAmount{0}
|
||||
: view.fees().accountReserve(currentOwnerCount, currentAccountCount);
|
||||
|
||||
auto const fullBalance = sle->getFieldAmount(sfBalance);
|
||||
|
||||
@@ -108,7 +293,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
|
||||
<< " amount=" << amount.getFullText()
|
||||
<< " fullBalance=" << fullBalance.getFullText()
|
||||
<< " balance=" << balance.getFullText() << " reserve=" << reserve
|
||||
<< " ownerCount=" << ownerCount << " ownerCountAdj=" << ownerCountAdj;
|
||||
<< " ownerCount=" << currentOwnerCount << " ownerCountAdj=" << ownerCountAdj;
|
||||
|
||||
return amount.xrp();
|
||||
}
|
||||
@@ -125,19 +310,193 @@ transferRate(ReadView const& view, AccountID const& issuer)
|
||||
}
|
||||
|
||||
void
|
||||
adjustOwnerCount(ApplyView& view, SLE::ref sle, std::int32_t amount, beast::Journal j)
|
||||
increaseOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (!sle)
|
||||
return;
|
||||
XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input");
|
||||
std::uint32_t const current{sle->getFieldU32(sfOwnerCount)};
|
||||
AccountID const id = (*sle)[sfAccount];
|
||||
std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j);
|
||||
view.adjustOwnerCountHook(id, current, adjusted);
|
||||
sle->at(sfOwnerCount) = adjusted;
|
||||
view.update(sle);
|
||||
XRPL_ASSERT(
|
||||
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
|
||||
"xrpl::increaseOwnerCount : count in signed delta range");
|
||||
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCountSigned(view, accountSle, sponsorSle, static_cast<std::int32_t>(count), j);
|
||||
}
|
||||
|
||||
void
|
||||
increaseOwnerCount(ApplyViewContext ctx, SLE::ref accountSle, std::uint32_t count, beast::Journal j)
|
||||
{
|
||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, accountSle);
|
||||
|
||||
// The sponsor's existence is validated by checkReserve/checkSponsor before
|
||||
// any owner-count mutation, so loading it here cannot fail.
|
||||
XRPL_ASSERT(
|
||||
sponsorExp.has_value(), "xrpl::increaseOwnerCount : sponsor validated before mutation");
|
||||
|
||||
increaseOwnerCount(ctx.view, accountSle, sponsorExp ? *sponsorExp : SLE::pointer(), count, j);
|
||||
}
|
||||
|
||||
void
|
||||
decreaseOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref sponsorSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
|
||||
"xrpl::decreaseOwnerCount : count in signed delta range");
|
||||
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCountSigned(view, accountSle, sponsorSle, -static_cast<std::int32_t>(count), j);
|
||||
}
|
||||
|
||||
void
|
||||
decreaseOwnerCountForObject(
|
||||
ApplyView& view,
|
||||
SLE::ref accountSle,
|
||||
SLE::ref objectSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
XRPL_ASSERT(objectSle, "xrpl::decreaseOwnerCountForObject : valid object sle");
|
||||
if (!objectSle)
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
bool const validObjectType = objectSle->getType() != ltACCOUNT_ROOT;
|
||||
XRPL_ASSERT(validObjectType, "xrpl::decreaseOwnerCountForObject : valid object sle type");
|
||||
if (!validObjectType)
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
SLE::ref sponsorSle = getLedgerEntryReserveSponsor(view, objectSle);
|
||||
decreaseOwnerCount(view, accountSle, sponsorSle, count, j);
|
||||
}
|
||||
|
||||
void
|
||||
adjustLoanBrokerOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::ref brokerSle,
|
||||
std::int32_t delta,
|
||||
beast::Journal j)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
brokerSle && brokerSle->getType() == ltLOAN_BROKER,
|
||||
"xrpl::adjustLoanBrokerOwnerCount : valid loan broker sle");
|
||||
if (!brokerSle || brokerSle->getType() != ltLOAN_BROKER)
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
XRPL_ASSERT(delta != 0, "xrpl::adjustLoanBrokerOwnerCount : nonzero delta input");
|
||||
if (delta == 0)
|
||||
return; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCountImpl(
|
||||
view, brokerSle, sfOwnerCount, brokerSle->getAccountID(sfAccount), delta, j);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
accountReserve(ReadView const& view, SLE::const_ref sle, beast::Journal j, Adjustment adj)
|
||||
{
|
||||
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::accountReserve : valid sle");
|
||||
|
||||
if (!view.rules().enabled(featureSponsor))
|
||||
{
|
||||
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::accountReserve : no account count delta");
|
||||
return view.fees().accountReserve(sle->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
|
||||
}
|
||||
std::uint32_t const currentOwnerCount = ownerCount(sle, j, adj.ownerCountDelta);
|
||||
std::uint32_t const currentAccountCount = accountCountImpl(sle, adj.accountCountDelta, j);
|
||||
|
||||
return view.fees().accountReserve(currentOwnerCount, currentAccountCount);
|
||||
}
|
||||
|
||||
TER
|
||||
checkReserve(
|
||||
ApplyViewContext ctx,
|
||||
SLE::const_ref accSle,
|
||||
XRPAmount accBalance,
|
||||
SLE::const_ref sponsorSle,
|
||||
Adjustment adj,
|
||||
beast::Journal j,
|
||||
TER insufReserveCode)
|
||||
{
|
||||
// TODO: swap to assert after fixCleanup3_2_0 is retired
|
||||
if (!accSle || accSle->getType() != ltACCOUNT_ROOT)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
XRPL_ASSERT(
|
||||
!isTesSuccess(insufReserveCode), "xrpl::checkReserve : insufReserveCode is not tesSUCCESS");
|
||||
if (ctx.view.rules().enabled(featureSponsor))
|
||||
{
|
||||
if (sponsorSle)
|
||||
{
|
||||
if (sponsorSle->getType() != ltACCOUNT_ROOT)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sle = ctx.view.read(
|
||||
keylet::sponsorship(
|
||||
sponsorSle->getAccountID(sfAccount), accSle->getAccountID(sfAccount)));
|
||||
|
||||
// A reserve-sponsored tx must carry a sponsor signature
|
||||
// (cosigning path) and/or have a pre-existing sponsorship SLE
|
||||
// (prefunded path). Absence of both is an internal invariant break.
|
||||
if (isReserveSponsored(ctx.tx) && !sle && !ctx.tx.isFieldPresent(sfSponsorSignature))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (sle)
|
||||
{
|
||||
auto const ownerCountAllowed = sle->getFieldU32(sfRemainingOwnerCount);
|
||||
if (adj.ownerCountDelta > 0 &&
|
||||
ownerCountAllowed < static_cast<std::uint32_t>(adj.ownerCountDelta))
|
||||
return insufReserveCode;
|
||||
}
|
||||
|
||||
auto const sponsorBalance = sponsorSle->getFieldAmount(sfBalance).xrp();
|
||||
XRPAmount const sponsorReserve = accountReserve(ctx.view, sponsorSle, j, adj);
|
||||
|
||||
if (sponsorBalance < sponsorReserve)
|
||||
return insufReserveCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
XRPAmount const reserve = accountReserve(ctx.view, accSle, j, adj);
|
||||
if (accBalance < reserve)
|
||||
return insufReserveCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!sponsorSle,
|
||||
"xrpl::checkReserve : featureSponsor disabled and sponsorSle not provided");
|
||||
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::checkReserve : accountCountDelta is 0");
|
||||
auto const reserve = ctx.view.fees().accountReserve(
|
||||
accSle->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
|
||||
if (accBalance < reserve)
|
||||
return insufReserveCode;
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
checkReserve(
|
||||
ApplyViewContext ctx,
|
||||
SLE::const_ref accSle,
|
||||
XRPAmount accBalance,
|
||||
Adjustment adj,
|
||||
beast::Journal j)
|
||||
{
|
||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, accSle);
|
||||
if (!sponsorExp)
|
||||
return sponsorExp.error(); // LCOV_EXCL_LINE
|
||||
return checkReserve(ctx, accSle, accBalance, *sponsorExp, adj, j);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
|
||||
AccountID
|
||||
pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
|
||||
{
|
||||
|
||||
@@ -97,7 +97,7 @@ deleteSLE(ApplyView& view, SLE::ref sleCredential, beast::Journal j)
|
||||
}
|
||||
|
||||
if (isOwner)
|
||||
adjustOwnerCount(view, sleAccount, -1, j);
|
||||
decreaseOwnerCountForObject(view, sleAccount, sleCredential, 1, j);
|
||||
|
||||
return tesSUCCESS;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
@@ -11,6 +10,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -125,29 +125,29 @@ canAddHolding(ReadView const& view, MPTIssue const& mptIssue)
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
MPTIssue const& mptIssue,
|
||||
beast::Journal journal)
|
||||
{
|
||||
auto const& mptID = mptIssue.getMptID();
|
||||
auto const mpt = view.peek(keylet::mptokenIssuance(mptID));
|
||||
auto const mpt = ctx.view.peek(keylet::mptokenIssuance(mptID));
|
||||
if (!mpt)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
if (mpt->isFlag(lsfMPTLocked))
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
if (view.peek(keylet::mptoken(mptID, accountID)))
|
||||
if (ctx.view.peek(keylet::mptoken(mptID, accountID)))
|
||||
return tecDUPLICATE;
|
||||
if (accountID == mptIssue.getIssuer())
|
||||
return tesSUCCESS;
|
||||
|
||||
return authorizeMPToken(view, priorBalance, mptID, accountID, journal);
|
||||
return authorizeMPToken(ctx, priorBalance, mptID, accountID, journal);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
authorizeMPToken(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
XRPAmount const& priorBalance,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
@@ -155,7 +155,7 @@ authorizeMPToken(
|
||||
std::uint32_t flags,
|
||||
std::optional<AccountID> holderID)
|
||||
{
|
||||
auto const sleAcct = view.peek(keylet::account(account));
|
||||
auto const sleAcct = ctx.view.peek(keylet::account(account));
|
||||
if (!sleAcct)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -170,19 +170,19 @@ authorizeMPToken(
|
||||
if ((flags & tfMPTUnauthorize) != 0u)
|
||||
{
|
||||
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
|
||||
auto const sleMpt = view.peek(mptokenKey);
|
||||
auto const sleMpt = ctx.view.peek(mptokenKey);
|
||||
if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0 ||
|
||||
(view.rules().enabled(fixCleanup3_1_3) &&
|
||||
(ctx.view.rules().enabled(fixCleanup3_1_3) &&
|
||||
(*sleMpt)[~sfLockedAmount].valueOr(0) != 0))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!view.dirRemove(
|
||||
if (!ctx.view.dirRemove(
|
||||
keylet::ownerDir(account), (*sleMpt)[sfOwnerNode], sleMpt->key(), false))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, sleAcct, -1, journal);
|
||||
decreaseOwnerCountForObject(ctx.view, sleAcct, sleMpt, 1, journal);
|
||||
|
||||
view.erase(sleMpt);
|
||||
ctx.view.erase(sleMpt);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -190,47 +190,57 @@ authorizeMPToken(
|
||||
// - add the new mptokenKey to the owner directory
|
||||
// - create the MPToken object for the holder
|
||||
|
||||
// A reserve sponsor only covers tx.Account's own objects.
|
||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, sleAcct);
|
||||
if (!sponsorExp)
|
||||
return sponsorExp.error(); // LCOV_EXCL_LINE
|
||||
auto const sponsorSle = *sponsorExp;
|
||||
|
||||
// The reserve that is required to create the MPToken. Note
|
||||
// that although the reserve increases with every item
|
||||
// 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::kZero)
|
||||
: view.fees().accountReserve(uOwnerCount + 1));
|
||||
|
||||
if (priorBalance < reserveCreate)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
// The "free-tier" shortcut (ownerCount < 2) does not apply once a sponsor is on
|
||||
// the tx — the sponsor must always cover the reserve (via balance or prefunded
|
||||
// budget), so this check always runs for sponsored transactions.
|
||||
if (sponsorSle || ownerCount(sleAcct, journal) >= 2)
|
||||
{
|
||||
if (auto const ret = checkReserve(
|
||||
ctx, sleAcct, priorBalance, sponsorSle, {.ownerCountDelta = 1}, journal);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Defensive check before we attempt to create MPToken for the issuer
|
||||
auto const mpt = view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
auto const mpt = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
if (!mpt || mpt->getAccountID(sfIssuer) == account)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::authorizeMPToken : invalid issuance or issuers token");
|
||||
if (view.rules().enabled(featureLendingProtocol))
|
||||
if (ctx.view.rules().enabled(featureLendingProtocol))
|
||||
return tecINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
|
||||
auto mptoken = std::make_shared<SLE>(mptokenKey);
|
||||
if (auto ter = dirLink(view, account, mptoken))
|
||||
if (auto ter = dirLink(ctx.view, account, mptoken))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
|
||||
(*mptoken)[sfAccount] = account;
|
||||
(*mptoken)[sfMPTokenIssuanceID] = mptIssuanceID;
|
||||
(*mptoken)[sfFlags] = 0;
|
||||
view.insert(mptoken);
|
||||
ctx.view.insert(mptoken);
|
||||
|
||||
// Update owner count.
|
||||
adjustOwnerCount(view, sleAcct, 1, journal);
|
||||
increaseOwnerCount(ctx.view, sleAcct, sponsorSle, 1, journal);
|
||||
addSponsorToLedgerEntry(mptoken, sponsorSle);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const sleMptIssuance = view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
auto const sleMptIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
if (!sleMptIssuance)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -240,7 +250,7 @@ authorizeMPToken(
|
||||
if (account != (*sleMptIssuance)[sfIssuer])
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sleMpt = view.peek(keylet::mptoken(mptIssuanceID, *holderID));
|
||||
auto const sleMpt = ctx.view.peek(keylet::mptoken(mptIssuanceID, *holderID));
|
||||
if (!sleMpt)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -263,13 +273,13 @@ authorizeMPToken(
|
||||
if (flagsIn != flagsOut)
|
||||
sleMpt->setFieldU32(sfFlags, flagsOut);
|
||||
|
||||
view.update(sleMpt);
|
||||
ctx.view.update(sleMpt);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
MPTIssue const& mptIssue,
|
||||
beast::Journal journal)
|
||||
@@ -279,7 +289,7 @@ removeEmptyHolding(
|
||||
// a token does exist, it will get deleted. If not, return success.
|
||||
bool const accountIsIssuer = accountID == mptIssue.getIssuer();
|
||||
auto const& mptID = mptIssue.getMptID();
|
||||
auto const mptoken = view.peek(keylet::mptoken(mptID, accountID));
|
||||
auto const mptoken = ctx.view.peek(keylet::mptoken(mptID, accountID));
|
||||
if (!mptoken)
|
||||
return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND;
|
||||
// Unlike a trust line, if the account is the issuer, and the token has a
|
||||
@@ -287,7 +297,7 @@ removeEmptyHolding(
|
||||
// accounting out of balance, so fail. Since this should be impossible
|
||||
// anyway, I'm not going to put any effort into it.
|
||||
if (mptoken->at(sfMPTAmount) != 0 ||
|
||||
(view.rules().enabled(fixCleanup3_1_3) && (*mptoken)[~sfLockedAmount].valueOr(0) != 0))
|
||||
(ctx.view.rules().enabled(fixCleanup3_1_3) && (*mptoken)[~sfLockedAmount].valueOr(0) != 0))
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
// Don't delete if the token still has confidential balances
|
||||
@@ -300,7 +310,7 @@ removeEmptyHolding(
|
||||
}
|
||||
|
||||
return authorizeMPToken(
|
||||
view,
|
||||
ctx,
|
||||
{}, // priorBalance
|
||||
mptID,
|
||||
accountID,
|
||||
@@ -419,13 +429,13 @@ requireAuth(
|
||||
|
||||
[[nodiscard]] TER
|
||||
enforceMPTokenAuthorization(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
XRPAmount const& priorBalance, // for MPToken authorization
|
||||
beast::Journal j)
|
||||
{
|
||||
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
if (!sleIssuance)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -437,7 +447,7 @@ enforceMPTokenAuthorization(
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const keylet = keylet::mptoken(mptIssuanceID, account);
|
||||
auto const sleToken = view.read(keylet); // NOTE: might be null
|
||||
auto const sleToken = ctx.view.read(keylet); // NOTE: might be null
|
||||
auto const maybeDomainID = sleIssuance->at(~sfDomainID);
|
||||
bool expired = false;
|
||||
bool const authorizedByDomain = [&]() -> bool {
|
||||
@@ -445,7 +455,7 @@ enforceMPTokenAuthorization(
|
||||
if (!maybeDomainID.has_value())
|
||||
return false; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ter = verifyValidDomain(view, account, *maybeDomainID, j);
|
||||
auto const ter = verifyValidDomain(ctx.view, account, *maybeDomainID, j);
|
||||
if (isTesSuccess(ter))
|
||||
return true;
|
||||
if (ter == tecEXPIRED)
|
||||
@@ -500,7 +510,7 @@ enforceMPTokenAuthorization(
|
||||
maybeDomainID.has_value() && sleToken == nullptr,
|
||||
"xrpl::enforceMPTokenAuthorization : new MPToken for domain");
|
||||
if (auto const err = authorizeMPToken(
|
||||
view,
|
||||
ctx,
|
||||
priorBalance, // priorBalance
|
||||
mptIssuanceID, // mptIssuanceID
|
||||
account, // account
|
||||
@@ -915,6 +925,7 @@ createMPToken(
|
||||
ApplyView& view,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
SLE::ref sponsorSle,
|
||||
std::uint32_t const flags)
|
||||
{
|
||||
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
|
||||
@@ -931,6 +942,8 @@ createMPToken(
|
||||
(*mptoken)[sfFlags] = flags;
|
||||
(*mptoken)[sfOwnerNode] = *ownerNode;
|
||||
|
||||
addSponsorToLedgerEntry(mptoken, sponsorSle);
|
||||
|
||||
view.insert(mptoken);
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -941,6 +954,7 @@ checkCreateMPT(
|
||||
xrpl::ApplyView& view,
|
||||
xrpl::MPTIssue const& mptIssue,
|
||||
xrpl::AccountID const& holder,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (mptIssue.getIssuer() == holder)
|
||||
@@ -950,7 +964,7 @@ checkCreateMPT(
|
||||
auto const mptokenID = keylet::mptoken(mptIssuanceID.key, holder);
|
||||
if (!view.exists(mptokenID))
|
||||
{
|
||||
if (auto const err = createMPToken(view, mptIssue.getMptID(), holder, 0);
|
||||
if (auto const err = createMPToken(view, mptIssue.getMptID(), holder, sponsorSle, 0);
|
||||
!isTesSuccess(err))
|
||||
{
|
||||
return err;
|
||||
@@ -960,7 +974,8 @@ checkCreateMPT(
|
||||
{
|
||||
return tecINTERNAL;
|
||||
}
|
||||
adjustOwnerCount(view, sleAcct, 1, j);
|
||||
|
||||
increaseOwnerCount(view, sleAcct, sponsorSle, 1, j);
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -269,11 +269,7 @@ insertToken(ApplyView& view, AccountID owner, STObject&& nft)
|
||||
// the NFT.
|
||||
SLE::pointer const page =
|
||||
getPageForToken(view, owner, nft[sfNFTokenID], [](ApplyView& view, AccountID const& owner) {
|
||||
adjustOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(owner)),
|
||||
1,
|
||||
beast::Journal{beast::Journal::getNullSink()});
|
||||
increaseOwnerCount(view, owner, {}, 1, beast::Journal{beast::Journal::getNullSink()});
|
||||
});
|
||||
|
||||
if (!page)
|
||||
@@ -411,21 +407,17 @@ removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID, S
|
||||
curr->setFieldArray(sfNFTokens, arr);
|
||||
view.update(curr);
|
||||
|
||||
int cnt = 0;
|
||||
std::uint32_t cnt = 0;
|
||||
|
||||
if (prev && mergePages(view, prev, curr))
|
||||
cnt--;
|
||||
++cnt;
|
||||
|
||||
if (next && mergePages(view, curr, next))
|
||||
cnt--;
|
||||
++cnt;
|
||||
|
||||
if (cnt != 0)
|
||||
{
|
||||
adjustOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(owner)),
|
||||
cnt,
|
||||
beast::Journal{beast::Journal::getNullSink()});
|
||||
decreaseOwnerCount(view, owner, {}, cnt, beast::Journal{beast::Journal::getNullSink()});
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -460,11 +452,7 @@ removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID, S
|
||||
curr->makeFieldAbsent(sfPreviousPageMin);
|
||||
}
|
||||
|
||||
adjustOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(owner)),
|
||||
-1,
|
||||
beast::Journal{beast::Journal::getNullSink()});
|
||||
decreaseOwnerCount(view, owner, {}, 1, beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
view.update(curr);
|
||||
view.erase(prev);
|
||||
@@ -502,7 +490,7 @@ removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID, S
|
||||
|
||||
view.erase(curr);
|
||||
|
||||
int cnt = 1;
|
||||
uint32_t cnt = 1;
|
||||
|
||||
// Since we're here, try to consolidate the previous and current pages
|
||||
// of the page we removed (if any) into one. mergePages() _should_
|
||||
@@ -519,11 +507,7 @@ removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID, S
|
||||
view.peek(Keylet(ltNFTOKEN_PAGE, next->key()))))
|
||||
cnt++;
|
||||
|
||||
adjustOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(owner)),
|
||||
-1 * cnt,
|
||||
beast::Journal{beast::Journal::getNullSink()});
|
||||
decreaseOwnerCount(view, owner, {}, cnt, beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -639,8 +623,7 @@ deleteTokenOffer(ApplyView& view, SLE::ref offer)
|
||||
false))
|
||||
return false;
|
||||
|
||||
adjustOwnerCount(
|
||||
view, view.peek(keylet::account(owner)), -1, beast::Journal{beast::Journal::getNullSink()});
|
||||
decreaseOwnerCount(view, owner, {}, 1, beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
view.erase(offer);
|
||||
return true;
|
||||
@@ -743,9 +726,11 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner)
|
||||
auto const newPrev = view.peek(Keylet(ltNFTOKEN_PAGE, *prevLink));
|
||||
if (!newPrev)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
Throw<std::runtime_error>(
|
||||
"NFTokenPage directory for " + to_string(owner) +
|
||||
" cannot be repaired. Unexpected link problem.");
|
||||
" cannot be repaired. Unexpected link problem.");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
newPrev->at(sfNextPageMin) = nextPage->key();
|
||||
view.update(newPrev);
|
||||
@@ -931,7 +916,7 @@ tokenOfferCreateApply(
|
||||
{
|
||||
Keylet const acctKeylet = keylet::account(acctID);
|
||||
if (auto const acct = view.read(acctKeylet);
|
||||
priorBalance < view.fees().accountReserve((*acct)[sfOwnerCount] + 1))
|
||||
priorBalance < accountReserve(view, acct, j, {.ownerCountDelta = 1}))
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
auto const offerID = keylet::nftokenOffer(acctID, seqProxy.value());
|
||||
@@ -983,7 +968,7 @@ tokenOfferCreateApply(
|
||||
}
|
||||
|
||||
// Update owner count.
|
||||
adjustOwnerCount(view, view.peek(acctKeylet), 1, j);
|
||||
increaseOwnerCount(view, acctID, {}, 1, j);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ offerDelete(ApplyView& view, SLE::ref sle, beast::Journal j)
|
||||
}
|
||||
}
|
||||
|
||||
adjustOwnerCount(view, view.peek(keylet::account(owner)), -1, j);
|
||||
decreaseOwnerCountForObject(view, owner, sle, 1, j);
|
||||
|
||||
view.erase(sle);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal
|
||||
XRPL_ASSERT(
|
||||
(*slep)[sfAmount] >= (*slep)[sfBalance], "xrpl::closeChannel : minimum channel amount");
|
||||
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
|
||||
adjustOwnerCount(view, sle, -1, j);
|
||||
decreaseOwnerCountForObject(view, sle, slep, 1, j);
|
||||
view.update(sle);
|
||||
|
||||
// Remove PayChan from ledger
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/AmountConversions.h>
|
||||
@@ -195,6 +196,7 @@ trustCreate(
|
||||
// Issuer should be the account being set.
|
||||
std::uint32_t uQualityIn,
|
||||
std::uint32_t uQualityOut,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j)
|
||||
{
|
||||
JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", "
|
||||
@@ -281,7 +283,9 @@ trustCreate(
|
||||
}
|
||||
|
||||
sleRippleState->setFieldU32(sfFlags, uFlags);
|
||||
adjustOwnerCount(view, sleAccount, 1, j);
|
||||
increaseOwnerCount(view, sleAccount, sponsorSle, 1, j);
|
||||
|
||||
addSponsorToLedgerEntry(sleRippleState, sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
|
||||
|
||||
// ONLY: Create ripple balance.
|
||||
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
|
||||
@@ -317,6 +321,9 @@ trustDelete(
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
removeSponsorFromLedgerEntry(sleRippleState, sfHighSponsor);
|
||||
removeSponsorFromLedgerEntry(sleRippleState, sfLowSponsor);
|
||||
|
||||
JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
|
||||
view.erase(sleRippleState);
|
||||
|
||||
@@ -369,11 +376,15 @@ updateTrustLine(
|
||||
{
|
||||
// VFALCO Where is the line being deleted?
|
||||
// Clear the reserve of the sender, possibly delete the line!
|
||||
adjustOwnerCount(view, sle, -1, j);
|
||||
auto const currentSponsor =
|
||||
getLedgerEntryReserveSponsor(view, state, bSenderHigh ? sfHighSponsor : sfLowSponsor);
|
||||
decreaseOwnerCount(view, sle, currentSponsor, 1, j);
|
||||
|
||||
// Clear reserve flag.
|
||||
state->clearFlag(senderReserveFlag);
|
||||
|
||||
removeSponsorFromLedgerEntry(state, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
||||
|
||||
// Balance is zero, receiver reserve is clear.
|
||||
if (!after && !state->isFlag(receiverReserveFlag))
|
||||
return true;
|
||||
@@ -381,12 +392,14 @@ updateTrustLine(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only used in tests
|
||||
TER
|
||||
issueIOU(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
Issue const& issue,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
@@ -472,6 +485,7 @@ issueIOU(
|
||||
limit,
|
||||
0,
|
||||
0,
|
||||
sponsorSle,
|
||||
j);
|
||||
}
|
||||
|
||||
@@ -620,7 +634,7 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
|
||||
|
||||
TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
Issue const& issue,
|
||||
@@ -632,30 +646,45 @@ addEmptyHolding(
|
||||
|
||||
auto const& issuerId = issue.getIssuer();
|
||||
auto const& currency = issue.currency;
|
||||
if (isGlobalFrozen(view, issuerId))
|
||||
if (isGlobalFrozen(ctx.view, issuerId))
|
||||
return tecFROZEN; // LCOV_EXCL_LINE
|
||||
|
||||
auto const& srcId = issuerId;
|
||||
auto const& dstId = accountID;
|
||||
auto const high = srcId > dstId;
|
||||
auto const index = keylet::trustLine(srcId, dstId, currency);
|
||||
auto const sleSrc = view.peek(keylet::account(srcId));
|
||||
auto const sleDst = view.peek(keylet::account(dstId));
|
||||
auto const sleSrc = ctx.view.peek(keylet::account(srcId));
|
||||
auto const sleDst = ctx.view.peek(keylet::account(dstId));
|
||||
if (!sleDst || !sleSrc)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
if (!sleSrc->isFlag(lsfDefaultRipple))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
// If the line already exists, don't create it again.
|
||||
if (view.read(index))
|
||||
if (ctx.view.read(index))
|
||||
return tecDUPLICATE;
|
||||
|
||||
// A reserve sponsor only covers tx.Account's own objects.
|
||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, sleDst);
|
||||
if (!sponsorExp)
|
||||
return sponsorExp.error(); // LCOV_EXCL_LINE
|
||||
auto const sponsorSle = *sponsorExp;
|
||||
|
||||
// Can the account cover the trust line reserve ?
|
||||
std::uint32_t const ownerCount = sleDst->at(sfOwnerCount);
|
||||
if (priorBalance < view.fees().accountReserve(ownerCount + 1))
|
||||
return tecNO_LINE_INSUF_RESERVE;
|
||||
if (auto const ret = checkReserve(
|
||||
ctx,
|
||||
sleDst,
|
||||
priorBalance,
|
||||
sponsorSle,
|
||||
{.ownerCountDelta = 1},
|
||||
journal,
|
||||
tecNO_LINE_INSUF_RESERVE);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return trustCreate(
|
||||
view,
|
||||
ctx.view,
|
||||
high,
|
||||
srcId,
|
||||
dstId,
|
||||
@@ -669,19 +698,20 @@ addEmptyHolding(
|
||||
/*saLimit=*/STAmount{Issue{currency, dstId}},
|
||||
/*uQualityIn=*/0,
|
||||
/*uQualityOut=*/0,
|
||||
sponsorSle,
|
||||
journal);
|
||||
}
|
||||
|
||||
TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
Issue const& issue,
|
||||
beast::Journal journal)
|
||||
{
|
||||
if (issue.native())
|
||||
{
|
||||
auto const sle = view.read(keylet::account(accountID));
|
||||
auto const sle = ctx.view.read(keylet::account(accountID));
|
||||
if (!sle)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -696,7 +726,7 @@ removeEmptyHolding(
|
||||
// If the account is the issuer, then no line should exist. Check anyway.
|
||||
// If a line does exist, it will get deleted. If not, return success.
|
||||
bool const accountIsIssuer = accountID == issue.account;
|
||||
auto const line = view.peek(keylet::trustLine(accountID, issue));
|
||||
auto const line = ctx.view.peek(keylet::trustLine(accountID, issue));
|
||||
if (!line)
|
||||
return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND;
|
||||
if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::kZero)
|
||||
@@ -706,33 +736,43 @@ removeEmptyHolding(
|
||||
if (line->isFlag(lsfLowReserve))
|
||||
{
|
||||
// Clear reserve for low account.
|
||||
auto sleLowAccount = view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
|
||||
auto sleLowAccount = ctx.view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
|
||||
if (!sleLowAccount)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, sleLowAccount, -1, journal);
|
||||
auto const currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfLowSponsor);
|
||||
|
||||
decreaseOwnerCount(ctx.view, sleLowAccount, currentLowSponsor, 1, journal);
|
||||
// It's not really necessary to clear the reserve flag, since the line
|
||||
// is about to be deleted, but this will make the metadata reflect an
|
||||
// accurate state at the time of deletion.
|
||||
line->clearFlag(lsfLowReserve);
|
||||
removeSponsorFromLedgerEntry(line, sfLowSponsor);
|
||||
}
|
||||
|
||||
if (line->isFlag(lsfHighReserve))
|
||||
{
|
||||
// Clear reserve for high account.
|
||||
auto sleHighAccount = view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
|
||||
auto sleHighAccount = ctx.view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
|
||||
if (!sleHighAccount)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, sleHighAccount, -1, journal);
|
||||
auto const currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfHighSponsor);
|
||||
|
||||
decreaseOwnerCount(ctx.view, sleHighAccount, currentHighSponsor, 1, journal);
|
||||
// It's not really necessary to clear the reserve flag, since the line
|
||||
// is about to be deleted, but this will make the metadata reflect an
|
||||
// accurate state at the time of deletion.
|
||||
line->clearFlag(lsfHighReserve);
|
||||
removeSponsorFromLedgerEntry(line, sfHighSponsor);
|
||||
}
|
||||
|
||||
return trustDelete(
|
||||
view, line, line->at(sfLowLimit)->getIssuer(), line->at(sfHighLimit)->getIssuer(), journal);
|
||||
ctx.view,
|
||||
line,
|
||||
line->at(sfLowLimit)->getIssuer(),
|
||||
line->at(sfHighLimit)->getIssuer(),
|
||||
journal);
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -768,6 +808,9 @@ deleteAMMTrustLine(
|
||||
if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
|
||||
return terNO_AMM;
|
||||
|
||||
auto const sponsorSle =
|
||||
getLedgerEntryReserveSponsor(view, sleState, !ammLow ? sfLowSponsor : sfHighSponsor);
|
||||
|
||||
if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter))
|
||||
{
|
||||
JLOG(j.error()) << "deleteAMMTrustLine: failed to delete the trustline.";
|
||||
@@ -778,7 +821,7 @@ deleteAMMTrustLine(
|
||||
if (!sleState->isFlag(uFlags))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, !ammLow ? sleLow : sleHigh, -1, j);
|
||||
decreaseOwnerCount(view, !ammLow ? sleLow : sleHigh, sponsorSle, 1, j);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
345
src/libxrpl/ledger/helpers/SponsorHelpers.cpp
Normal file
345
src/libxrpl/ledger/helpers/SponsorHelpers.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
bool
|
||||
isReserveSponsorAllowed(TxType txType)
|
||||
{
|
||||
// Transaction types explicitly allow-listed for reserve sponsorship, for
|
||||
// v1. Lazily-initialized function-local static: constructed once on first
|
||||
// use, with no startup cost paid by clients that never call this.
|
||||
static std::unordered_set<TxType> const kReserveSponsorAllowed = {
|
||||
ttDELEGATE_SET,
|
||||
ttDEPOSIT_PREAUTH,
|
||||
ttPAYMENT,
|
||||
ttSIGNER_LIST_SET,
|
||||
ttCHECK_CANCEL,
|
||||
ttCHECK_CASH,
|
||||
ttCHECK_CREATE,
|
||||
ttESCROW_CANCEL,
|
||||
ttESCROW_CREATE,
|
||||
ttESCROW_FINISH,
|
||||
ttPAYCHAN_CLAIM,
|
||||
ttPAYCHAN_CREATE,
|
||||
ttPAYCHAN_FUND,
|
||||
ttCLAWBACK,
|
||||
ttMPTOKEN_AUTHORIZE,
|
||||
ttMPTOKEN_ISSUANCE_CREATE,
|
||||
ttMPTOKEN_ISSUANCE_DESTROY,
|
||||
ttMPTOKEN_ISSUANCE_SET,
|
||||
ttTRUST_SET,
|
||||
ttCREDENTIAL_ACCEPT,
|
||||
ttCREDENTIAL_CREATE,
|
||||
ttCREDENTIAL_DELETE,
|
||||
ttACCOUNT_SET,
|
||||
ttREGULAR_KEY_SET,
|
||||
ttSPONSORSHIP_TRANSFER,
|
||||
};
|
||||
return kReserveSponsorAllowed.contains(txType);
|
||||
}
|
||||
|
||||
std::optional<AccountID>
|
||||
getTxReserveSponsorID(STTx const& tx)
|
||||
{
|
||||
if (tx.isFieldPresent(sfSponsor) && isReserveSponsored(tx))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
getCurrentTransactionRules()->enabled( // NOLINT(bugprone-unchecked-optional-access)
|
||||
featureSponsor),
|
||||
"xrpl::getTxReserveSponsorID : sponsor exists + Sponsor enabled");
|
||||
return tx.getAccountID(sfSponsor);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::expected<SLE::pointer, TER>
|
||||
getTxReserveSponsor(ApplyViewContext ctx)
|
||||
{
|
||||
auto const sponsorID = getTxReserveSponsorID(ctx.tx);
|
||||
if (sponsorID)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
ctx.view.rules().enabled(featureSponsor),
|
||||
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
|
||||
auto sle = ctx.view.peek(keylet::account(*sponsorID));
|
||||
|
||||
// already checked in Transactor::checkSponsor
|
||||
if (!sle)
|
||||
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
||||
return sle;
|
||||
}
|
||||
return SLE::pointer();
|
||||
}
|
||||
|
||||
std::expected<SLE::const_pointer, TER>
|
||||
getTxReserveSponsor(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
auto const sponsorID = getTxReserveSponsorID(tx);
|
||||
if (sponsorID)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
view.rules().enabled(featureSponsor),
|
||||
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
|
||||
auto sle = view.read(keylet::account(*sponsorID));
|
||||
|
||||
// already checked in Transactor::checkSponsor
|
||||
if (!sle)
|
||||
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
||||
return sle;
|
||||
}
|
||||
return SLE::pointer();
|
||||
}
|
||||
|
||||
std::expected<SLE::pointer, TER>
|
||||
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::const_ref accountSle)
|
||||
{
|
||||
// A reserve sponsor only covers tx.Account's own objects.
|
||||
if (ctx.view.rules().enabled(fixCleanup3_2_0))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
accountSle && accountSle->getType() == ltACCOUNT_ROOT,
|
||||
"xrpl::getEffectiveTxReserveSponsor : accountSle exists and is account type");
|
||||
}
|
||||
else
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
accountSle &&
|
||||
((accountSle->getType() == ltACCOUNT_ROOT) || (accountSle->getType() == ltESCROW)),
|
||||
"xrpl::getEffectiveTxReserveSponsor : accountSle exists and is account type");
|
||||
}
|
||||
|
||||
if (isPseudoAccount(accountSle) || accountSle->getAccountID(sfAccount) != ctx.tx[sfAccount])
|
||||
return SLE::pointer();
|
||||
return getTxReserveSponsor(ctx);
|
||||
}
|
||||
|
||||
std::optional<AccountID>
|
||||
getLedgerEntryReserveSponsorID(SLE::const_ref sle, SF_ACCOUNT const& field)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(sle &&
|
||||
((sle->getType() == ltRIPPLE_STATE && (field == sfHighSponsor || field == sfLowSponsor)) ||
|
||||
(sle->getType() != ltRIPPLE_STATE && field == sfSponsor))),
|
||||
"xrpl::getLedgerEntryReserveSponsorID : correct sfield");
|
||||
|
||||
if (sle->isFieldPresent(field))
|
||||
return sle->getAccountID(field);
|
||||
return {};
|
||||
}
|
||||
|
||||
SLE::pointer
|
||||
getLedgerEntryReserveSponsor(ApplyView& view, SLE::const_ref sle, SF_ACCOUNT const& field)
|
||||
{
|
||||
auto const sponsorID = getLedgerEntryReserveSponsorID(sle, field);
|
||||
if (sponsorID)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
view.rules().enabled(featureSponsor),
|
||||
"xrpl::getLedgerEntryReserveSponsor : sponsor exists + Sponsor enabled");
|
||||
return view.peek(keylet::account(*sponsorID));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
addSponsorToLedgerEntry(SLE::ref sle, SLE::const_ref sponsorSle, SF_ACCOUNT const& field)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(sle->getType() == ltRIPPLE_STATE && (field == sfHighSponsor || field == sfLowSponsor)) ||
|
||||
(sle->getType() != ltRIPPLE_STATE && field == sfSponsor),
|
||||
"addSponsorToLedgerEntry : Invalid field to the LedgerEntry");
|
||||
if (sponsorSle)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
getCurrentTransactionRules()->enabled( // NOLINT(bugprone-unchecked-optional-access)
|
||||
featureSponsor),
|
||||
"xrpl::addSponsorToLedgerEntry : sponsor exists + Sponsor enabled");
|
||||
sle->setAccountID(field, sponsorSle->getAccountID(sfAccount));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::ref sle, SF_ACCOUNT const& field)
|
||||
{
|
||||
// getTxReserveSponsor yields a null pointer when the tx is not
|
||||
// reserve-sponsored, so addSponsorToLedgerEntry becomes a no-op then. The
|
||||
// error case (tecINTERNAL) is an already-checked invariant; skip stamping.
|
||||
auto const sponsorSle = getTxReserveSponsor(ctx);
|
||||
if (sponsorSle && *sponsorSle)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
ctx.view.rules().enabled(featureSponsor),
|
||||
"xrpl::addSponsorToLedgerEntry : sponsor exists + Sponsor enabled");
|
||||
addSponsorToLedgerEntry(sle, *sponsorSle, field);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const& field)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(sle->getType() == ltRIPPLE_STATE && (field == sfHighSponsor || field == sfLowSponsor)) ||
|
||||
(sle->getType() != ltRIPPLE_STATE && field == sfSponsor),
|
||||
"removeSponsorFromLedgerEntry : Invalid field to the LedgerEntry");
|
||||
if (sle->isFieldPresent(field))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
getCurrentTransactionRules()->enabled( // NOLINT(bugprone-unchecked-optional-access)
|
||||
featureSponsor),
|
||||
"xrpl::removeSponsorFromLedgerEntry : sponsor exists + Sponsor enabled");
|
||||
sle->makeFieldAbsent(field);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isLedgerEntryOwner(ReadView const& view, SLE const& sle, AccountID const& account)
|
||||
{
|
||||
switch (sle.getType())
|
||||
{
|
||||
case ltCHECK:
|
||||
case ltESCROW:
|
||||
case ltPAYCHAN:
|
||||
case ltMPTOKEN:
|
||||
case ltDELEGATE:
|
||||
case ltDEPOSIT_PREAUTH:
|
||||
return sle.getAccountID(sfAccount) == account;
|
||||
case ltMPTOKEN_ISSUANCE:
|
||||
return sle.getAccountID(sfIssuer) == account;
|
||||
case ltSIGNER_LIST: {
|
||||
auto const signerList = view.read(keylet::signerList(account));
|
||||
if (!signerList)
|
||||
return false;
|
||||
return signerList->key() == sle.key();
|
||||
}
|
||||
case ltCREDENTIAL: {
|
||||
auto const& ownerField = sle.isFlag(lsfAccepted) ? sfSubject : sfIssuer;
|
||||
return sle.getAccountID(ownerField) == account;
|
||||
}
|
||||
case ltRIPPLE_STATE: {
|
||||
if (sle.isFlag(lsfHighReserve))
|
||||
{
|
||||
auto const highAccount = sle.getFieldAmount(sfHighLimit).getIssuer();
|
||||
if (highAccount == account)
|
||||
return true;
|
||||
}
|
||||
if (sle.isFlag(lsfLowReserve))
|
||||
{
|
||||
auto const lowAccount = sle.getFieldAmount(sfLowLimit).getIssuer();
|
||||
if (lowAccount == account)
|
||||
return true;
|
||||
}
|
||||
// Reachable: the sponsee may be a third party or the side of the
|
||||
// line that holds no reserve (e.g. the issuer). Callers map this
|
||||
// to tecNO_PERMISSION.
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::isLedgerEntryOwner : object is not supported by sponsorship.");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
isLedgerEntrySupportedBySponsorship(SLE const& sle)
|
||||
{
|
||||
switch (sle.getType())
|
||||
{
|
||||
case ltCHECK:
|
||||
case ltESCROW:
|
||||
case ltPAYCHAN:
|
||||
case ltMPTOKEN:
|
||||
case ltDELEGATE:
|
||||
case ltDEPOSIT_PREAUTH:
|
||||
case ltMPTOKEN_ISSUANCE:
|
||||
case ltSIGNER_LIST:
|
||||
case ltCREDENTIAL:
|
||||
case ltRIPPLE_STATE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
getLedgerEntryOwnerCount(SLE const& sle)
|
||||
{
|
||||
switch (sle.getType())
|
||||
{
|
||||
case ltORACLE: {
|
||||
return calculateOracleReserve(sle.getFieldArray(sfPriceDataSeries));
|
||||
}
|
||||
// Vaults require 2 owner counts (the vault and a pseudo-account)
|
||||
case ltVAULT:
|
||||
return 2;
|
||||
case ltSIGNER_LIST: {
|
||||
// Mirror SignerListSet's owner-count accounting so that create and
|
||||
// delete agree. Modern lists (post-MultiSignReserve) carry the
|
||||
// lsfOneOwnerCount flag and cost a single owner count. Legacy
|
||||
// pre-MultiSignReserve lists cost 2 + signer_count owner counts
|
||||
if (sle.isFlag(lsfOneOwnerCount))
|
||||
return 1;
|
||||
return 2 + static_cast<std::uint32_t>(sle.getFieldArray(sfSignerEntries).size());
|
||||
}
|
||||
case ltACCOUNT_ROOT:
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("AccountRoots are not supported by object sponsorship.");
|
||||
return 0;
|
||||
// LCOV_EXCL_STOP
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
SF_ACCOUNT const&
|
||||
getLedgerEntrySponsorField(SLE const& sle, AccountID const& owner)
|
||||
{
|
||||
switch (sle.getType())
|
||||
{
|
||||
case ltRIPPLE_STATE: {
|
||||
if (sle.isFlag(lsfHighReserve))
|
||||
{
|
||||
auto const highAccount = sle.getFieldAmount(sfHighLimit).getIssuer();
|
||||
if (highAccount == owner)
|
||||
return sfHighSponsor;
|
||||
}
|
||||
if (sle.isFlag(lsfLowReserve))
|
||||
{
|
||||
auto const lowAccount = sle.getFieldAmount(sfLowLimit).getIssuer();
|
||||
if (lowAccount == owner)
|
||||
return sfLowSponsor;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::getLedgerEntrySponsorField : unknown owner for RippleState");
|
||||
return sfSponsor;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
default:
|
||||
return sfSponsor;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Concepts.h>
|
||||
@@ -571,7 +572,7 @@ canAddHolding(ReadView const& view, Asset const& asset)
|
||||
|
||||
TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
Asset const& asset,
|
||||
@@ -579,21 +580,21 @@ addEmptyHolding(
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
|
||||
return addEmptyHolding(view, accountID, priorBalance, issue, journal);
|
||||
return addEmptyHolding(ctx, accountID, priorBalance, issue, journal);
|
||||
},
|
||||
asset.value());
|
||||
}
|
||||
|
||||
TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
ApplyViewContext ctx,
|
||||
AccountID const& accountID,
|
||||
Asset const& asset,
|
||||
beast::Journal journal)
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
|
||||
return removeEmptyHolding(view, accountID, issue, journal);
|
||||
return removeEmptyHolding(ctx, accountID, issue, journal);
|
||||
},
|
||||
asset.value());
|
||||
}
|
||||
@@ -647,6 +648,7 @@ directSendNoFeeIOU(
|
||||
AccountID const& uReceiverID,
|
||||
STAmount const& saAmount,
|
||||
bool bCheckIssuer,
|
||||
SLE::ref sponsorSle,
|
||||
beast::Journal j)
|
||||
{
|
||||
AccountID const& issuer = saAmount.getIssuer();
|
||||
@@ -717,7 +719,12 @@ directSendNoFeeIOU(
|
||||
// Sender quality out is 0.
|
||||
{
|
||||
// Clear the reserve of the sender, possibly delete the line!
|
||||
adjustOwnerCount(view, view.peek(keylet::account(uSenderID)), -1, j);
|
||||
auto const currentSponsor = getLedgerEntryReserveSponsor(
|
||||
view, sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
||||
decreaseOwnerCount(view, view.peek(keylet::account(uSenderID)), currentSponsor, 1, j);
|
||||
|
||||
removeSponsorFromLedgerEntry(
|
||||
sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
||||
|
||||
// Clear reserve flag.
|
||||
sleRippleState->clearFlag(senderReserveFlag);
|
||||
@@ -780,6 +787,7 @@ directSendNoFeeIOU(
|
||||
saReceiverLimit,
|
||||
0,
|
||||
0,
|
||||
sponsorSle,
|
||||
j);
|
||||
}
|
||||
|
||||
@@ -794,6 +802,7 @@ directSendNoLimitIOU(
|
||||
STAmount const& saAmount,
|
||||
STAmount& saActual,
|
||||
beast::Journal j,
|
||||
SLE::ref sponsorSle,
|
||||
WaiveTransferFee waiveFee)
|
||||
{
|
||||
auto const& issuer = saAmount.getIssuer();
|
||||
@@ -806,7 +815,8 @@ directSendNoLimitIOU(
|
||||
if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount())
|
||||
{
|
||||
// Direct send: redeeming IOUs and/or sending own IOUs.
|
||||
auto const ter = directSendNoFeeIOU(view, uSenderID, uReceiverID, saAmount, false, j);
|
||||
auto const ter =
|
||||
directSendNoFeeIOU(view, uSenderID, uReceiverID, saAmount, false, sponsorSle, j);
|
||||
if (!isTesSuccess(ter))
|
||||
return ter;
|
||||
saActual = saAmount;
|
||||
@@ -824,10 +834,12 @@ directSendNoLimitIOU(
|
||||
<< to_string(uReceiverID) << " : deliver=" << saAmount.getFullText()
|
||||
<< " cost=" << saActual.getFullText();
|
||||
|
||||
TER terResult = directSendNoFeeIOU(view, issuer, uReceiverID, saAmount, true, j);
|
||||
TER terResult = directSendNoFeeIOU(view, issuer, uReceiverID, saAmount, true, sponsorSle, j);
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = directSendNoFeeIOU(view, uSenderID, issuer, saActual, true, j);
|
||||
{
|
||||
terResult = directSendNoFeeIOU(view, uSenderID, issuer, saActual, true, sponsorSle, j);
|
||||
}
|
||||
|
||||
return terResult;
|
||||
}
|
||||
@@ -870,7 +882,8 @@ directSendNoLimitMultiIOU(
|
||||
if (senderID == issuer || receiverID == issuer || issuer == noAccount())
|
||||
{
|
||||
// Direct send: redeeming IOUs and/or sending own IOUs.
|
||||
if (auto const ter = directSendNoFeeIOU(view, senderID, receiverID, amount, false, j);
|
||||
if (auto const ter =
|
||||
directSendNoFeeIOU(view, senderID, receiverID, amount, false, {}, j);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
actual += amount;
|
||||
@@ -894,14 +907,14 @@ directSendNoLimitMultiIOU(
|
||||
<< to_string(receiverID) << " : deliver=" << amount.getFullText()
|
||||
<< " cost=" << actual.getFullText();
|
||||
|
||||
if (TER const terResult = directSendNoFeeIOU(view, issuer, receiverID, amount, true, j))
|
||||
if (TER const terResult = directSendNoFeeIOU(view, issuer, receiverID, amount, true, {}, j))
|
||||
return terResult;
|
||||
}
|
||||
|
||||
if (senderID != issuer && takeFromSender)
|
||||
{
|
||||
if (TER const terResult =
|
||||
directSendNoFeeIOU(view, senderID, issuer, takeFromSender, true, j))
|
||||
directSendNoFeeIOU(view, senderID, issuer, takeFromSender, true, {}, j))
|
||||
return terResult;
|
||||
}
|
||||
|
||||
@@ -915,6 +928,7 @@ accountSendIOU(
|
||||
AccountID const& uReceiverID,
|
||||
STAmount const& saAmount,
|
||||
beast::Journal j,
|
||||
SLE::ref sponsorSle,
|
||||
WaiveTransferFee waiveFee)
|
||||
{
|
||||
if (view.rules().enabled(fixAMMv1_1))
|
||||
@@ -946,7 +960,8 @@ accountSendIOU(
|
||||
JLOG(j.trace()) << "accountSendIOU: " << to_string(uSenderID) << " -> "
|
||||
<< to_string(uReceiverID) << " : " << saAmount.getFullText();
|
||||
|
||||
return directSendNoLimitIOU(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee);
|
||||
return directSendNoLimitIOU(
|
||||
view, uSenderID, uReceiverID, saAmount, saActual, j, sponsorSle, waiveFee);
|
||||
}
|
||||
|
||||
/* XRP send which does not check reserve and can do pure adjustment.
|
||||
@@ -1475,7 +1490,7 @@ directSendNoFee(
|
||||
{
|
||||
return saAmount.asset().visit(
|
||||
[&](Issue const&) {
|
||||
return directSendNoFeeIOU(view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j);
|
||||
return directSendNoFeeIOU(view, uSenderID, uReceiverID, saAmount, bCheckIssuer, {}, j);
|
||||
},
|
||||
[&](MPTIssue const&) {
|
||||
XRPL_ASSERT(!bCheckIssuer, "xrpl::directSendNoFee : not checking issuer");
|
||||
@@ -1490,12 +1505,13 @@ accountSend(
|
||||
AccountID const& uReceiverID,
|
||||
STAmount const& saAmount,
|
||||
beast::Journal j,
|
||||
SLE::ref sponsorSle,
|
||||
WaiveTransferFee waiveFee,
|
||||
AllowMPTOverflow allowOverflow)
|
||||
{
|
||||
return saAmount.asset().visit(
|
||||
[&](Issue const&) {
|
||||
return accountSendIOU(view, uSenderID, uReceiverID, saAmount, j, waiveFee);
|
||||
return accountSendIOU(view, uSenderID, uReceiverID, saAmount, j, sponsorSle, waiveFee);
|
||||
},
|
||||
[&](MPTIssue const&) {
|
||||
return accountSendMPT(
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
@@ -71,9 +70,6 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
NftokenBuyOffers = 'h',
|
||||
NftokenSellOffers = 'i',
|
||||
Amm = 'A',
|
||||
Bridge = 'H',
|
||||
XchainClaimId = 'Q',
|
||||
XchainCreateAccountClaimId = 'K',
|
||||
Did = 'I',
|
||||
Oracle = 'R',
|
||||
MPTokenIssuance = '~',
|
||||
@@ -84,6 +80,7 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
Vault = 'V',
|
||||
LoanBroker = 'l', // lower-case L
|
||||
Loan = 'L',
|
||||
Sponsorship = '>',
|
||||
|
||||
// No longer used or supported. Left here to reserve the space to avoid accidental reuse.
|
||||
Contract [[deprecated]] = 'c',
|
||||
@@ -326,6 +323,12 @@ signerList(AccountID const& account) noexcept
|
||||
return signerList(account, 0);
|
||||
}
|
||||
|
||||
Keylet
|
||||
sponsorship(AccountID const& sponsor, AccountID const& sponsee) noexcept
|
||||
{
|
||||
return {ltSPONSORSHIP, indexHash(LedgerNameSpace::Sponsorship, sponsor, sponsee)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
check(AccountID const& id, std::uint32_t seq) noexcept
|
||||
{
|
||||
@@ -475,44 +478,6 @@ delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept
|
||||
return {ltDELEGATE, indexHash(LedgerNameSpace::Delegate, account, authorizedAccount)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType)
|
||||
{
|
||||
// A door account can support multiple bridges. On the locking chain
|
||||
// there can only be one bridge per lockingChainCurrency. On the issuing
|
||||
// chain there can only be one bridge per issuingChainCurrency.
|
||||
auto const& issue = bridge.issue(chainType);
|
||||
return {ltBRIDGE, indexHash(LedgerNameSpace::Bridge, bridge.door(chainType), issue.currency)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
{
|
||||
return {
|
||||
ltXCHAIN_OWNED_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XchainClaimId,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
{
|
||||
return {
|
||||
ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XchainCreateAccountClaimId,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
did(AccountID const& account) noexcept
|
||||
{
|
||||
|
||||
@@ -63,58 +63,6 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfPrice, SoeRequired},
|
||||
{sfAuthAccounts, SoeOptional}});
|
||||
|
||||
add(sfXChainClaimAttestationCollectionElement.jsonName,
|
||||
sfXChainClaimAttestationCollectionElement.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainCreateAccountAttestationCollectionElement.jsonName,
|
||||
sfXChainCreateAccountAttestationCollectionElement.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfXChainClaimProofSig.jsonName,
|
||||
sfXChainClaimProofSig.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainCreateAccountProofSig.jsonName,
|
||||
sfXChainCreateAccountProofSig.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfAuthAccount.jsonName,
|
||||
sfAuthAccount.getCode(),
|
||||
{
|
||||
@@ -160,6 +108,14 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfTxnSignature, SoeOptional},
|
||||
{sfSigners, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfSponsorSignature.jsonName.cStr(),
|
||||
sfSponsorSignature.getCode(),
|
||||
{
|
||||
{sfSigningPubKey, SoeOptional},
|
||||
{sfTxnSignature, SoeOptional},
|
||||
{sfSigners, SoeOptional},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -15,6 +15,7 @@ LedgerFormats::getCommonFields()
|
||||
{sfLedgerIndex, SoeOptional},
|
||||
{sfLedgerEntryType, SoeRequired},
|
||||
{sfFlags, SoeRequired},
|
||||
{sfSponsor, SoeOptional},
|
||||
};
|
||||
return kCommonFields;
|
||||
}
|
||||
|
||||
@@ -634,16 +634,16 @@ STObject::getAccountID(SField const& field) const
|
||||
}
|
||||
|
||||
AccountID
|
||||
STObject::getFeePayer() const
|
||||
STObject::getInitiator() const
|
||||
{
|
||||
// If sfDelegate is present, the delegate account is the payer
|
||||
// If sfDelegate is present, the delegate account is the initiator
|
||||
// note: if a delegate is specified, its authorization to act on behalf of the account is
|
||||
// enforced in `Transactor::invokeCheckPermission`
|
||||
// cryptographic signature validity is checked separately (e.g., in `Transactor::checkSign`)
|
||||
if (isFieldPresent(sfDelegate))
|
||||
return getAccountID(sfDelegate);
|
||||
|
||||
// Default payer
|
||||
// Default initiator
|
||||
return getAccountID(sfAccount);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
@@ -956,18 +955,6 @@ parseLeaf(
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_XCHAIN_BRIDGE:
|
||||
try
|
||||
{
|
||||
ret = detail::makeStvar<STXChainBridge>(STXChainBridge(field, value));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalidData(jsonName, fieldName);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_CURRENCY:
|
||||
try
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/Sign.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
@@ -271,6 +272,13 @@ STTx::checkSign(Rules const& rules) const
|
||||
return std::unexpected("Counterparty: " + ret.error());
|
||||
}
|
||||
|
||||
if (isFieldPresent(sfSponsorSignature))
|
||||
{
|
||||
auto const sponsorSignatureObj = getFieldObject(sfSponsorSignature);
|
||||
if (auto const ret = checkSign(rules, sponsorSignatureObj); !ret)
|
||||
return std::unexpected("Sponsor: " + ret.error());
|
||||
}
|
||||
|
||||
// Verify the batch signer signatures here too, so they are cached with the
|
||||
// rest of signature checking (checkValidity / SF_SIGGOOD) and stay out of
|
||||
// the transaction engine. Gated on a batch (batchTxnIds_ seated) that
|
||||
@@ -551,7 +559,7 @@ STTx::checkMultiSign(Rules const& rules, STObject const& sigObject) const
|
||||
// For delegated transactions sfDelegate is the account whose signer list is checked,
|
||||
// the delegate account itself can not be among the signers.
|
||||
auto const txnAccountID =
|
||||
&sigObject != this ? std::nullopt : std::optional<AccountID>(getFeePayer());
|
||||
&sigObject != this ? std::nullopt : std::optional<AccountID>(getInitiator());
|
||||
|
||||
// We can ease the computational load inside the loop a bit by
|
||||
// pre-constructing part of the data that we hash. Fill a Serializer
|
||||
@@ -603,6 +611,15 @@ STTx::getBatchTransactionIDs() const
|
||||
return *batchTxnIds_;
|
||||
}
|
||||
|
||||
AccountID
|
||||
STTx::getFeePayerID() const
|
||||
{
|
||||
if (isFieldPresent(sfSponsor) && ((getFieldU32(sfSponsorFlags) & spfSponsorFee) != 0u))
|
||||
return at(sfSponsor);
|
||||
|
||||
return getInitiator();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static bool
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -217,9 +216,6 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args)
|
||||
case STI_ISSUE:
|
||||
construct<STIssue>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_XCHAIN_BRIDGE:
|
||||
construct<STXChainBridge>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_CURRENCY:
|
||||
construct<STCurrency>(std::forward<Args>(args)...);
|
||||
return;
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <boost/format/free_funcs.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
STXChainBridge::STXChainBridge() : STBase{sfXChainBridge}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(SField const& name) : STBase{name}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(
|
||||
AccountID const& srcChainDoor,
|
||||
Issue const& srcChainIssue,
|
||||
AccountID const& dstChainDoor,
|
||||
Issue const& dstChainIssue)
|
||||
: STBase{sfXChainBridge}
|
||||
, lockingChainDoor_{sfLockingChainDoor, srcChainDoor}
|
||||
, lockingChainIssue_{sfLockingChainIssue, srcChainIssue}
|
||||
, issuingChainDoor_{sfIssuingChainDoor, dstChainDoor}
|
||||
, issuingChainIssue_{sfIssuingChainIssue, dstChainIssue}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(STObject const& o)
|
||||
: STBase{sfXChainBridge}
|
||||
, lockingChainDoor_{sfLockingChainDoor, o[sfLockingChainDoor]}
|
||||
, lockingChainIssue_{sfLockingChainIssue, o[sfLockingChainIssue]}
|
||||
, issuingChainDoor_{sfIssuingChainDoor, o[sfIssuingChainDoor]}
|
||||
, issuingChainIssue_{sfIssuingChainIssue, o[sfIssuingChainIssue]}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(json::Value const& v) : STXChainBridge{sfXChainBridge, v}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(SField const& name, json::Value const& v) : STBase{name}
|
||||
{
|
||||
if (!v.isObject())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"STXChainBridge can only be specified with a 'object' Json value");
|
||||
}
|
||||
|
||||
auto checkExtra = [](json::Value const& v) {
|
||||
static auto const kBridgeJson =
|
||||
xrpl::STXChainBridge().getJson(xrpl::JsonOptions::Values::None);
|
||||
for (auto it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
std::string const name = it.memberName();
|
||||
if (!kBridgeJson.isMember(name))
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge extra field detected: " + name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
checkExtra(v);
|
||||
|
||||
json::Value const& lockingChainDoorStr = v[jss::LockingChainDoor];
|
||||
json::Value const& lockingChainIssue = v[jss::LockingChainIssue];
|
||||
json::Value const& issuingChainDoorStr = v[jss::IssuingChainDoor];
|
||||
json::Value const& issuingChainIssue = v[jss::IssuingChainIssue];
|
||||
|
||||
if (!lockingChainDoorStr.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge LockingChainDoor must be a string Json value");
|
||||
}
|
||||
if (!issuingChainDoorStr.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge IssuingChainDoor must be a string Json value");
|
||||
}
|
||||
|
||||
auto const lockingChainDoor = parseBase58<AccountID>(lockingChainDoorStr.asString());
|
||||
auto const issuingChainDoor = parseBase58<AccountID>(issuingChainDoorStr.asString());
|
||||
if (!lockingChainDoor)
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge LockingChainDoor must be a valid account");
|
||||
}
|
||||
if (!issuingChainDoor)
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge IssuingChainDoor must be a valid account");
|
||||
}
|
||||
|
||||
lockingChainDoor_ = STAccount{sfLockingChainDoor, *lockingChainDoor};
|
||||
lockingChainIssue_ = STIssue{sfLockingChainIssue, issueFromJson(lockingChainIssue)};
|
||||
issuingChainDoor_ = STAccount{sfIssuingChainDoor, *issuingChainDoor};
|
||||
issuingChainIssue_ = STIssue{sfIssuingChainIssue, issueFromJson(issuingChainIssue)};
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(SerialIter& sit, SField const& name)
|
||||
: STBase{name}
|
||||
, lockingChainDoor_{sit, sfLockingChainDoor}
|
||||
, lockingChainIssue_{sit, sfLockingChainIssue}
|
||||
, issuingChainDoor_{sit, sfIssuingChainDoor}
|
||||
, issuingChainIssue_{sit, sfIssuingChainIssue}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
STXChainBridge::add(Serializer& s) const
|
||||
{
|
||||
lockingChainDoor_.add(s);
|
||||
lockingChainIssue_.add(s);
|
||||
issuingChainDoor_.add(s);
|
||||
issuingChainIssue_.add(s);
|
||||
}
|
||||
|
||||
json::Value
|
||||
STXChainBridge::getJson(JsonOptions jo) const
|
||||
{
|
||||
json::Value v;
|
||||
v[jss::LockingChainDoor] = lockingChainDoor_.getJson(jo);
|
||||
v[jss::LockingChainIssue] = lockingChainIssue_.getJson(jo);
|
||||
v[jss::IssuingChainDoor] = issuingChainDoor_.getJson(jo);
|
||||
v[jss::IssuingChainIssue] = issuingChainIssue_.getJson(jo);
|
||||
return v;
|
||||
}
|
||||
|
||||
std::string
|
||||
STXChainBridge::getText() const
|
||||
{
|
||||
return str(
|
||||
boost::format("{ %s = %s, %s = %s, %s = %s, %s = %s }") % sfLockingChainDoor.getName() %
|
||||
lockingChainDoor_.getText() % sfLockingChainIssue.getName() % lockingChainIssue_.getText() %
|
||||
sfIssuingChainDoor.getName() % issuingChainDoor_.getText() % sfIssuingChainIssue.getName() %
|
||||
issuingChainIssue_.getText());
|
||||
}
|
||||
|
||||
STObject
|
||||
STXChainBridge::toSTObject() const
|
||||
{
|
||||
STObject o{sfXChainBridge};
|
||||
o[sfLockingChainDoor] = lockingChainDoor_;
|
||||
o[sfLockingChainIssue] = lockingChainIssue_;
|
||||
o[sfIssuingChainDoor] = issuingChainDoor_;
|
||||
o[sfIssuingChainIssue] = issuingChainIssue_;
|
||||
return o;
|
||||
}
|
||||
|
||||
SerializedTypeID
|
||||
STXChainBridge::getSType() const
|
||||
{
|
||||
return STI_XCHAIN_BRIDGE;
|
||||
}
|
||||
|
||||
bool
|
||||
STXChainBridge::isEquivalent(STBase const& t) const
|
||||
{
|
||||
auto const* v = dynamic_cast<STXChainBridge const*>(&t);
|
||||
return (v != nullptr) && (*v == *this);
|
||||
}
|
||||
|
||||
bool
|
||||
STXChainBridge::isDefault() const
|
||||
{
|
||||
return lockingChainDoor_.isDefault() && lockingChainIssue_.isDefault() &&
|
||||
issuingChainDoor_.isDefault() && issuingChainIssue_.isDefault();
|
||||
}
|
||||
|
||||
std::unique_ptr<STXChainBridge>
|
||||
STXChainBridge::construct(SerialIter& sit, SField const& name)
|
||||
{
|
||||
return std::make_unique<STXChainBridge>(sit, name);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STXChainBridge::copy(std::size_t n, void* buf) const
|
||||
{
|
||||
return emplace(n, buf, *this);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STXChainBridge::move(std::size_t n, void* buf)
|
||||
{
|
||||
return emplace(n, buf, std::move(*this));
|
||||
}
|
||||
} // namespace xrpl
|
||||
@@ -107,6 +107,7 @@ transResults()
|
||||
MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."),
|
||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||
MAKE_ERROR(tecBAD_PROOF, "Proof cannot be verified"),
|
||||
MAKE_ERROR(tecNO_SPONSOR_PERMISSION, "Sponsor has not authorized this transaction."),
|
||||
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
@@ -220,6 +221,7 @@ transResults()
|
||||
MAKE_ERROR(terADDRESS_COLLISION, "Failed to allocate an unique account address."),
|
||||
MAKE_ERROR(terNO_DELEGATE_PERMISSION, "Delegated account lacks permission to perform this transaction."),
|
||||
MAKE_ERROR(terLOCKED, "Fund is locked."),
|
||||
MAKE_ERROR(terNO_PERMISSION, "No permission to perform requested operation."),
|
||||
|
||||
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||
};
|
||||
|
||||
@@ -30,6 +30,9 @@ TxFormats::getCommonFields()
|
||||
{sfSigners, SoeOptional}, // submit_multisigned
|
||||
{sfNetworkID, SoeOptional},
|
||||
{sfDelegate, SoeOptional},
|
||||
{sfSponsor, SoeOptional},
|
||||
{sfSponsorFlags, SoeOptional},
|
||||
{sfSponsorSignature, SoeOptional},
|
||||
};
|
||||
return kCommonFields;
|
||||
}
|
||||
|
||||
@@ -1,706 +0,0 @@
|
||||
#include <xrpl/protocol/XChainAttestations.h>
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/json_get_or_throw.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
namespace Attestations {
|
||||
|
||||
AttestationBase::AttestationBase(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend)
|
||||
: attestationSignerAccount{attestationSignerAccount}
|
||||
, publicKey{publicKey}
|
||||
, signature{std::move(signature)}
|
||||
, sendingAccount{sendingAccount}
|
||||
, sendingAmount{std::move(sendingAmount)}
|
||||
, rewardAccount{rewardAccount}
|
||||
, wasLockingChainSend{wasLockingChainSend}
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationBase::equalHelper(AttestationBase const& lhs, AttestationBase const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.attestationSignerAccount,
|
||||
lhs.publicKey,
|
||||
lhs.signature,
|
||||
lhs.sendingAccount,
|
||||
lhs.sendingAmount,
|
||||
lhs.rewardAccount,
|
||||
lhs.wasLockingChainSend) ==
|
||||
std::tie(
|
||||
rhs.attestationSignerAccount,
|
||||
rhs.publicKey,
|
||||
rhs.signature,
|
||||
rhs.sendingAccount,
|
||||
rhs.sendingAmount,
|
||||
rhs.rewardAccount,
|
||||
rhs.wasLockingChainSend);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationBase::sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs)
|
||||
{
|
||||
return std::tie(lhs.sendingAccount, lhs.sendingAmount, lhs.wasLockingChainSend) ==
|
||||
std::tie(rhs.sendingAccount, rhs.sendingAmount, rhs.wasLockingChainSend);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationBase::verify(STXChainBridge const& bridge) const
|
||||
{
|
||||
std::vector<std::uint8_t> const msg = message(bridge);
|
||||
return xrpl::verify(publicKey, makeSlice(msg), signature);
|
||||
}
|
||||
|
||||
AttestationBase::AttestationBase(STObject const& o)
|
||||
: attestationSignerAccount{o[sfAttestationSignerAccount]}
|
||||
, publicKey{o[sfPublicKey]}
|
||||
, signature{o[sfSignature]}
|
||||
, sendingAccount{o[sfAccount]}
|
||||
, sendingAmount{o[sfAmount]}
|
||||
, rewardAccount{o[sfAttestationRewardAccount]}
|
||||
, wasLockingChainSend{bool(o[sfWasLockingChainSend])}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationBase::AttestationBase(json::Value const& v)
|
||||
: attestationSignerAccount{json::getOrThrow<AccountID>(v, sfAttestationSignerAccount)}
|
||||
, publicKey{json::getOrThrow<PublicKey>(v, sfPublicKey)}
|
||||
, signature{json::getOrThrow<Buffer>(v, sfSignature)}
|
||||
, sendingAccount{json::getOrThrow<AccountID>(v, sfAccount)}
|
||||
, sendingAmount{json::getOrThrow<STAmount>(v, sfAmount)}
|
||||
, rewardAccount{json::getOrThrow<AccountID>(v, sfAttestationRewardAccount)}
|
||||
, wasLockingChainSend{json::getOrThrow<bool>(v, sfWasLockingChainSend)}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AttestationBase::addHelper(STObject& o) const
|
||||
{
|
||||
o[sfAttestationSignerAccount] = attestationSignerAccount;
|
||||
o[sfPublicKey] = publicKey;
|
||||
o[sfSignature] = signature;
|
||||
o[sfAmount] = sendingAmount;
|
||||
o[sfAccount] = sendingAccount;
|
||||
o[sfAttestationRewardAccount] = rewardAccount;
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend;
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst)
|
||||
: AttestationBase(
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
std::move(signature),
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend)
|
||||
, claimID{claimId}
|
||||
, dst{dst}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst)
|
||||
: AttestationClaim{
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
Buffer{},
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend,
|
||||
claimId,
|
||||
dst}
|
||||
{
|
||||
auto const toSign = message(bridge);
|
||||
signature = sign(publicKey, secretKey, makeSlice(toSign));
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(STObject const& o)
|
||||
: AttestationBase(o), claimID{o[sfXChainClaimID]}, dst{o[~sfDestination]}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(json::Value const& v)
|
||||
: AttestationBase{v}, claimID{json::getOrThrow<std::uint64_t>(v, sfXChainClaimID)}
|
||||
{
|
||||
if (v.isMember(sfDestination.getJsonName()))
|
||||
dst = json::getOrThrow<AccountID>(v, sfDestination);
|
||||
}
|
||||
|
||||
STObject
|
||||
AttestationClaim::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainClaimAttestationCollectionElement);
|
||||
addHelper(o);
|
||||
o[sfXChainClaimID] = claimID;
|
||||
if (dst)
|
||||
o[sfDestination] = *dst;
|
||||
return o;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationClaim::message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimID,
|
||||
std::optional<AccountID> const& dst)
|
||||
{
|
||||
STObject o{sfGeneric};
|
||||
// Serialize in SField order to make python serializers easier to write
|
||||
o[sfXChainClaimID] = claimID;
|
||||
o[sfAmount] = sendingAmount;
|
||||
if (dst)
|
||||
o[sfDestination] = *dst;
|
||||
o[sfOtherChainSource] = sendingAccount;
|
||||
o[sfAttestationRewardAccount] = rewardAccount;
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0;
|
||||
o[sfXChainBridge] = bridge;
|
||||
|
||||
Serializer s;
|
||||
o.add(s);
|
||||
|
||||
return std::move(s.modData());
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationClaim::message(STXChainBridge const& bridge) const
|
||||
{
|
||||
return AttestationClaim::message(
|
||||
bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationClaim::validAmounts() const
|
||||
{
|
||||
return isLegalNet(sendingAmount);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationClaim::sameEvent(AttestationClaim const& rhs) const
|
||||
{
|
||||
return AttestationClaim::sameEventHelper(*this, rhs) &&
|
||||
tie(claimID, dst) == tie(rhs.claimID, rhs.dst);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(AttestationClaim const& lhs, AttestationClaim const& rhs)
|
||||
{
|
||||
return AttestationClaim::equalHelper(lhs, rhs) &&
|
||||
tie(lhs.claimID, lhs.dst) == tie(rhs.claimID, rhs.dst);
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(STObject const& o)
|
||||
: AttestationBase(o)
|
||||
, createCount{o[sfXChainAccountCreateCount]}
|
||||
, toCreate{o[sfDestination]}
|
||||
, rewardAmount{o[sfSignatureReward]}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(json::Value const& v)
|
||||
: AttestationBase{v}
|
||||
, createCount{json::getOrThrow<std::uint64_t>(v, sfXChainAccountCreateCount)}
|
||||
, toCreate{json::getOrThrow<AccountID>(v, sfDestination)}
|
||||
, rewardAmount{json::getOrThrow<STAmount>(v, sfSignatureReward)}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate)
|
||||
: AttestationBase(
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
std::move(signature),
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend)
|
||||
, createCount{createCount}
|
||||
, toCreate{toCreate}
|
||||
, rewardAmount{std::move(rewardAmount)}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate)
|
||||
: AttestationCreateAccount{
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
Buffer{},
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend,
|
||||
createCount,
|
||||
toCreate}
|
||||
{
|
||||
auto const toSign = message(bridge);
|
||||
signature = sign(publicKey, secretKey, makeSlice(toSign));
|
||||
}
|
||||
|
||||
STObject
|
||||
AttestationCreateAccount::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainCreateAccountAttestationCollectionElement);
|
||||
addHelper(o);
|
||||
|
||||
o[sfXChainAccountCreateCount] = createCount;
|
||||
o[sfDestination] = toCreate;
|
||||
o[sfSignatureReward] = rewardAmount;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationCreateAccount::message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& dst)
|
||||
{
|
||||
STObject o{sfGeneric};
|
||||
// Serialize in SField order to make python serializers easier to write
|
||||
o[sfXChainAccountCreateCount] = createCount;
|
||||
o[sfAmount] = sendingAmount;
|
||||
o[sfSignatureReward] = rewardAmount;
|
||||
o[sfDestination] = dst;
|
||||
o[sfOtherChainSource] = sendingAccount;
|
||||
o[sfAttestationRewardAccount] = rewardAccount;
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0;
|
||||
o[sfXChainBridge] = bridge;
|
||||
|
||||
Serializer s;
|
||||
o.add(s);
|
||||
|
||||
return std::move(s.modData());
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationCreateAccount::message(STXChainBridge const& bridge) const
|
||||
{
|
||||
return AttestationCreateAccount::message(
|
||||
bridge,
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend,
|
||||
createCount,
|
||||
toCreate);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationCreateAccount::validAmounts() const
|
||||
{
|
||||
return isLegalNet(rewardAmount) && isLegalNet(sendingAmount);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationCreateAccount::sameEvent(AttestationCreateAccount const& rhs) const
|
||||
{
|
||||
return AttestationCreateAccount::sameEventHelper(*this, rhs) &&
|
||||
std::tie(createCount, toCreate, rewardAmount) ==
|
||||
std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs)
|
||||
{
|
||||
return AttestationCreateAccount::equalHelper(lhs, rhs) &&
|
||||
std::tie(lhs.createCount, lhs.toCreate, lhs.rewardAmount) ==
|
||||
std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount);
|
||||
}
|
||||
|
||||
} // namespace Attestations
|
||||
|
||||
SField const& XChainClaimAttestation::arrayFieldName{sfXChainClaimAttestations};
|
||||
SField const& XChainCreateAccountAttestation::arrayFieldName{sfXChainCreateAccountAttestations};
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<AccountID> const& dst)
|
||||
: keyAccount(keyAccount)
|
||||
, publicKey(publicKey)
|
||||
, amount(sfAmount, amount)
|
||||
, rewardAccount(rewardAccount)
|
||||
, wasLockingChainSend(wasLockingChainSend)
|
||||
, dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(
|
||||
STAccount const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAccount const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<STAccount> const& dst)
|
||||
: XChainClaimAttestation{
|
||||
keyAccount.value(),
|
||||
publicKey,
|
||||
amount,
|
||||
rewardAccount.value(),
|
||||
wasLockingChainSend,
|
||||
dst ? std::optional<AccountID>{dst->value()} : std::nullopt}
|
||||
{
|
||||
}
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(STObject const& o)
|
||||
: XChainClaimAttestation{
|
||||
o[sfAttestationSignerAccount],
|
||||
PublicKey{o[sfPublicKey]},
|
||||
o[sfAmount],
|
||||
o[sfAttestationRewardAccount],
|
||||
o[sfWasLockingChainSend] != 0,
|
||||
o[~sfDestination]} {};
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(json::Value const& v)
|
||||
: XChainClaimAttestation{
|
||||
json::getOrThrow<AccountID>(v, sfAttestationSignerAccount),
|
||||
json::getOrThrow<PublicKey>(v, sfPublicKey),
|
||||
json::getOrThrow<STAmount>(v, sfAmount),
|
||||
json::getOrThrow<AccountID>(v, sfAttestationRewardAccount),
|
||||
json::getOrThrow<bool>(v, sfWasLockingChainSend),
|
||||
std::nullopt}
|
||||
{
|
||||
if (v.isMember(sfDestination.getJsonName()))
|
||||
dst = json::getOrThrow<AccountID>(v, sfDestination);
|
||||
};
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(
|
||||
XChainClaimAttestation::TSignedAttestation const& claimAtt)
|
||||
: XChainClaimAttestation{
|
||||
claimAtt.attestationSignerAccount,
|
||||
claimAtt.publicKey,
|
||||
claimAtt.sendingAmount,
|
||||
claimAtt.rewardAccount,
|
||||
claimAtt.wasLockingChainSend,
|
||||
claimAtt.dst}
|
||||
{
|
||||
}
|
||||
|
||||
STObject
|
||||
XChainClaimAttestation::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainClaimProofSig);
|
||||
o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount};
|
||||
o[sfPublicKey] = publicKey;
|
||||
o[sfAmount] = STAmount{sfAmount, amount};
|
||||
o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount};
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend;
|
||||
if (dst)
|
||||
o[sfDestination] = STAccount{sfDestination, *dst};
|
||||
return o;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.keyAccount,
|
||||
lhs.publicKey,
|
||||
lhs.amount,
|
||||
lhs.rewardAccount,
|
||||
lhs.wasLockingChainSend,
|
||||
lhs.dst) ==
|
||||
std::tie(
|
||||
rhs.keyAccount,
|
||||
rhs.publicKey,
|
||||
rhs.amount,
|
||||
rhs.rewardAccount,
|
||||
rhs.wasLockingChainSend,
|
||||
rhs.dst);
|
||||
}
|
||||
|
||||
XChainClaimAttestation::MatchFields::MatchFields(
|
||||
XChainClaimAttestation::TSignedAttestation const& att)
|
||||
: amount{att.sendingAmount}, wasLockingChainSend{att.wasLockingChainSend}, dst{att.dst}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationMatch
|
||||
XChainClaimAttestation::match(XChainClaimAttestation::MatchFields const& rhs) const
|
||||
{
|
||||
if (std::tie(amount, wasLockingChainSend) != std::tie(rhs.amount, rhs.wasLockingChainSend))
|
||||
return AttestationMatch::NonDstMismatch;
|
||||
if (dst != rhs.dst)
|
||||
return AttestationMatch::MatchExceptDst;
|
||||
return AttestationMatch::Match;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
AccountID const& dst)
|
||||
: keyAccount(keyAccount)
|
||||
, publicKey(publicKey)
|
||||
, amount(sfAmount, amount)
|
||||
, rewardAmount(sfSignatureReward, rewardAmount)
|
||||
, rewardAccount(rewardAccount)
|
||||
, wasLockingChainSend(wasLockingChainSend)
|
||||
, dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(STObject const& o)
|
||||
: XChainCreateAccountAttestation{
|
||||
o[sfAttestationSignerAccount],
|
||||
PublicKey{o[sfPublicKey]},
|
||||
o[sfAmount],
|
||||
o[sfSignatureReward],
|
||||
o[sfAttestationRewardAccount],
|
||||
o[sfWasLockingChainSend] != 0,
|
||||
o[sfDestination]} {};
|
||||
|
||||
XChainCreateAccountAttestation ::XChainCreateAccountAttestation(json::Value const& v)
|
||||
: XChainCreateAccountAttestation{
|
||||
json::getOrThrow<AccountID>(v, sfAttestationSignerAccount),
|
||||
json::getOrThrow<PublicKey>(v, sfPublicKey),
|
||||
json::getOrThrow<STAmount>(v, sfAmount),
|
||||
json::getOrThrow<STAmount>(v, sfSignatureReward),
|
||||
json::getOrThrow<AccountID>(v, sfAttestationRewardAccount),
|
||||
json::getOrThrow<bool>(v, sfWasLockingChainSend),
|
||||
json::getOrThrow<AccountID>(v, sfDestination)}
|
||||
{
|
||||
}
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(
|
||||
XChainCreateAccountAttestation::TSignedAttestation const& createAtt)
|
||||
: XChainCreateAccountAttestation{
|
||||
createAtt.attestationSignerAccount,
|
||||
createAtt.publicKey,
|
||||
createAtt.sendingAmount,
|
||||
createAtt.rewardAmount,
|
||||
createAtt.rewardAccount,
|
||||
createAtt.wasLockingChainSend,
|
||||
createAtt.toCreate}
|
||||
{
|
||||
}
|
||||
|
||||
STObject
|
||||
XChainCreateAccountAttestation::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainCreateAccountProofSig);
|
||||
|
||||
o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount};
|
||||
o[sfPublicKey] = publicKey;
|
||||
o[sfAmount] = STAmount{sfAmount, amount};
|
||||
o[sfSignatureReward] = STAmount{sfSignatureReward, rewardAmount};
|
||||
o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount};
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend;
|
||||
o[sfDestination] = STAccount{sfDestination, dst};
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
XChainCreateAccountAttestation::MatchFields::MatchFields(
|
||||
XChainCreateAccountAttestation::TSignedAttestation const& att)
|
||||
: amount{att.sendingAmount}
|
||||
, rewardAmount(att.rewardAmount)
|
||||
, wasLockingChainSend{att.wasLockingChainSend}
|
||||
, dst{att.toCreate}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationMatch
|
||||
XChainCreateAccountAttestation::match(XChainCreateAccountAttestation::MatchFields const& rhs) const
|
||||
{
|
||||
if (std::tie(amount, rewardAmount, wasLockingChainSend) !=
|
||||
std::tie(rhs.amount, rhs.rewardAmount, rhs.wasLockingChainSend))
|
||||
return AttestationMatch::NonDstMismatch;
|
||||
if (dst != rhs.dst)
|
||||
return AttestationMatch::MatchExceptDst;
|
||||
return AttestationMatch::Match;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.keyAccount,
|
||||
lhs.publicKey,
|
||||
lhs.amount,
|
||||
lhs.rewardAmount,
|
||||
lhs.rewardAccount,
|
||||
lhs.wasLockingChainSend,
|
||||
lhs.dst) ==
|
||||
std::tie(
|
||||
rhs.keyAccount,
|
||||
rhs.publicKey,
|
||||
rhs.amount,
|
||||
rhs.rewardAmount,
|
||||
rhs.rewardAccount,
|
||||
rhs.wasLockingChainSend,
|
||||
rhs.dst);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::XChainAttestationsBase(
|
||||
XChainAttestationsBase<TAttestation>::AttCollection&& atts)
|
||||
: attestations_{std::move(atts)}
|
||||
{
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::const_iterator
|
||||
XChainAttestationsBase<TAttestation>::begin() const
|
||||
{
|
||||
return attestations_.begin();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::const_iterator
|
||||
XChainAttestationsBase<TAttestation>::end() const
|
||||
{
|
||||
return attestations_.end();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::iterator
|
||||
XChainAttestationsBase<TAttestation>::begin()
|
||||
{
|
||||
return attestations_.begin();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::iterator
|
||||
XChainAttestationsBase<TAttestation>::end()
|
||||
{
|
||||
return attestations_.end();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::XChainAttestationsBase(json::Value const& v)
|
||||
{
|
||||
if (!v.isObject())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"XChainAttestationsBase can only be specified with an 'object' "
|
||||
"Json value");
|
||||
}
|
||||
|
||||
attestations_ = [&] {
|
||||
auto const jAtts = v[jss::attestations];
|
||||
|
||||
if (jAtts.size() > kMaxAttestations)
|
||||
Throw<std::runtime_error>("XChainAttestationsBase exceeded max number of attestations");
|
||||
|
||||
std::vector<TAttestation> r;
|
||||
r.reserve(jAtts.size());
|
||||
for (auto const& a : jAtts)
|
||||
r.emplace_back(a);
|
||||
return r;
|
||||
}();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::XChainAttestationsBase(STArray const& arr)
|
||||
{
|
||||
if (arr.size() > kMaxAttestations)
|
||||
Throw<std::runtime_error>("XChainAttestationsBase exceeded max number of attestations");
|
||||
|
||||
attestations_.reserve(arr.size());
|
||||
for (auto const& o : arr)
|
||||
attestations_.emplace_back(o);
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
STArray
|
||||
XChainAttestationsBase<TAttestation>::toSTArray() const
|
||||
{
|
||||
STArray r{TAttestation::arrayFieldName, attestations_.size()};
|
||||
for (auto const& e : attestations_)
|
||||
r.emplaceBack(e.toSTObject());
|
||||
return r;
|
||||
}
|
||||
|
||||
template class XChainAttestationsBase<XChainClaimAttestation>;
|
||||
template class XChainAttestationsBase<XChainCreateAccountAttestation>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/OfferHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -41,6 +42,7 @@
|
||||
#include <xrpl/tx/apply.h>
|
||||
#include <xrpl/tx/applySteps.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
@@ -167,6 +169,58 @@ preflightCheckSimulateKeys(ApplyFlags flags, STObject const& sigObject, beast::J
|
||||
|
||||
} // namespace detail
|
||||
|
||||
static NotTEC
|
||||
preflight1Sponsor(PreflightContext const& ctx)
|
||||
{
|
||||
bool const hasSponsor = ctx.tx.isFieldPresent(sfSponsor);
|
||||
bool const hasSponsorFlags = ctx.tx.isFieldPresent(sfSponsorFlags);
|
||||
bool const hasSponsorSig = ctx.tx.isFieldPresent(sfSponsorSignature);
|
||||
|
||||
if ((hasSponsor || hasSponsorFlags || hasSponsorSig) && !ctx.rules.enabled(featureSponsor))
|
||||
return temDISABLED;
|
||||
|
||||
if (hasSponsor != hasSponsorFlags)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "preflight1: sponsor and sponsor flags mismatch";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
if (hasSponsorSig && (!hasSponsor || !hasSponsorFlags))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "preflight1: sponsor signature without sponsor definition";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (hasSponsorFlags)
|
||||
{
|
||||
auto const sponsorFlags = ctx.tx.getFieldU32(sfSponsorFlags);
|
||||
if (((sponsorFlags & spfSponsorFlagMask) != 0u) || sponsorFlags == 0)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "preflight1: invalid sponsor flags";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
// Reserve sponsorship is only permitted for an explicit allow-list of
|
||||
// transaction types, for v1. All other tx types reject spfSponsorReserve here.
|
||||
if (isReserveSponsored(ctx.tx))
|
||||
{
|
||||
if (!isReserveSponsorAllowed(ctx.tx.getTxnType()))
|
||||
{
|
||||
JLOG(ctx.j.debug())
|
||||
<< "preflight1: spfSponsorReserve not allowed for this transaction type";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSponsor && ctx.tx.getAccountID(sfSponsor) == ctx.tx.getAccountID(sfAccount))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "preflight1: Sponsor account cannot be the same as the account";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
/** Performs early sanity checks on the account and fee fields */
|
||||
NotTEC
|
||||
Transactor::preflight1(PreflightContext const& ctx, std::uint32_t flagMask)
|
||||
@@ -230,6 +284,9 @@ Transactor::preflight1(PreflightContext const& ctx, std::uint32_t flagMask)
|
||||
if (ctx.tx.isFlag(tfInnerBatchTxn) != ctx.parentBatchId.has_value())
|
||||
return temINVALID_INNER_BATCH;
|
||||
|
||||
if (auto const ter = preflight1Sponsor(ctx); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -343,6 +400,44 @@ Transactor::checkPermission(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Transactor::checkSponsor(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
if (!tx.isFieldPresent(sfSponsor))
|
||||
return tesSUCCESS;
|
||||
|
||||
// Reserve sponsorship with permissioned delegation is disallowed.
|
||||
if (tx.isFieldPresent(sfDelegate) && isReserveSponsored(tx))
|
||||
return temINVALID;
|
||||
|
||||
if (!view.exists(keylet::account(tx.getAccountID(sfSponsor))))
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
// Skip Sponsorship existence checks if the sponsor has signed the transaction - this
|
||||
// transaction is valid regardless of the Sponsorship object.
|
||||
// The use of the Sponsorship object is properly handled in
|
||||
// getFeePayer/checkReserve/increaseOwnerCount/decreaseOwnerCount.
|
||||
if (tx.isFieldPresent(sfSponsorSignature))
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the transaction contains sfDelegate, the Sponsorship object should be
|
||||
// between the sponsor and the delegate.
|
||||
auto const sponsorshipSle =
|
||||
view.read(keylet::sponsorship(tx.getAccountID(sfSponsor), tx.getInitiator()));
|
||||
|
||||
// sponsorship object missing for pre-funded (no co-signing) tx
|
||||
if (!sponsorshipSle)
|
||||
return terNO_PERMISSION;
|
||||
|
||||
if (isFeeSponsored(tx) && sponsorshipSle->isFlag(lsfSponsorshipRequireSignForFee))
|
||||
return terNO_PERMISSION;
|
||||
|
||||
if (isReserveSponsored(tx) && sponsorshipSle->isFlag(lsfSponsorshipRequireSignForReserve))
|
||||
return terNO_PERMISSION;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
@@ -351,6 +446,7 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
// The computation has two parts:
|
||||
// * The base fee, which is the same for most transactions.
|
||||
// * The additional cost of each multisignature on the transaction.
|
||||
// * The additional cost of each multisignature on the sponsor.
|
||||
XRPAmount const baseFee = view.fees().base;
|
||||
|
||||
// Each signer adds one more baseFee to the minimum required fee
|
||||
@@ -358,7 +454,15 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
std::size_t const signerCount =
|
||||
tx.isFieldPresent(sfSigners) ? tx.getFieldArray(sfSigners).size() : 0;
|
||||
|
||||
return baseFee + (signerCount * baseFee);
|
||||
std::size_t sponsorSignerCount = 0;
|
||||
if (tx.isFieldPresent(sfSponsorSignature))
|
||||
{
|
||||
auto const sponsorObj = tx.getFieldObject(sfSponsorSignature);
|
||||
if (sponsorObj.isFieldPresent(sfSigners))
|
||||
sponsorSignerCount += sponsorObj.getFieldArray(sfSigners).size();
|
||||
}
|
||||
|
||||
return baseFee + ((signerCount + sponsorSignerCount) * baseFee);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
@@ -437,12 +541,51 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
|
||||
if (feePaid == beast::kZero)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const id = ctx.tx.getFeePayer();
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
auto const feePayer = getFeePayer(ctx.view, ctx.tx);
|
||||
auto const payerSle = ctx.view.read(feePayer.keylet);
|
||||
|
||||
auto const balance = (*sle)[sfBalance].xrp();
|
||||
if (!payerSle)
|
||||
{
|
||||
if (feePayer.type == FeePayerType::SponsorPreFunded)
|
||||
{
|
||||
// Sanity check: already checked in checkSponsor
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
return terNO_ACCOUNT;
|
||||
}
|
||||
|
||||
XRPAmount maxSpendable = beast::kZero;
|
||||
|
||||
if (feePayer.type == FeePayerType::SponsorPreFunded)
|
||||
{
|
||||
if (payerSle->getType() != ltSPONSORSHIP)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (payerSle->isFieldPresent(feePayer.balanceField))
|
||||
maxSpendable = payerSle->getFieldAmount(feePayer.balanceField).xrp();
|
||||
|
||||
if (payerSle->isFieldPresent(sfMaxFee))
|
||||
{
|
||||
auto const cap = payerSle->getFieldAmount(sfMaxFee).xrp();
|
||||
maxSpendable = std::min(maxSpendable, cap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (payerSle->getType() != ltACCOUNT_ROOT)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
||||
{
|
||||
auto const sponsorReserve = accountReserve(ctx.view, payerSle, ctx.j);
|
||||
maxSpendable = payerSle->getFieldAmount(sfBalance).xrp() - sponsorReserve;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxSpendable = payerSle->getFieldAmount(feePayer.balanceField).xrp();
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Because preclaim evaluates against a static readview, it
|
||||
// does not reflect fee deductions from other transactions paid by
|
||||
@@ -451,12 +594,12 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
|
||||
// transactions, this check may pass optimistically.
|
||||
// The fee shortfall will be handled by the Transactor::reset mechanism,
|
||||
// which caps the fee to the remaining actual balance.
|
||||
if (balance < feePaid)
|
||||
if (maxSpendable < feePaid)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Insufficient balance:" << " balance=" << to_string(balance)
|
||||
JLOG(ctx.j.trace()) << "Insufficient balance:" << " balance=" << to_string(maxSpendable)
|
||||
<< " paid=" << to_string(feePaid);
|
||||
|
||||
if ((balance > beast::kZero) && !ctx.view.open())
|
||||
if ((maxSpendable > beast::kZero) && !ctx.view.open())
|
||||
{
|
||||
// Closed ledger, non-zero balance, less than fee
|
||||
return tecINSUFF_FEE;
|
||||
@@ -473,16 +616,72 @@ Transactor::payFee()
|
||||
{
|
||||
auto const feePaid = ctx_.tx[sfFee].xrp();
|
||||
|
||||
auto const feePayer = ctx_.tx.getFeePayer();
|
||||
auto const sle = view().peek(keylet::account(feePayer));
|
||||
auto const feePayer = getFeePayer(view(), ctx_.tx);
|
||||
auto const sle = view().peek(feePayer.keylet);
|
||||
|
||||
JLOG(j_.trace()) << "Fee payer: " + to_string(feePayer.id);
|
||||
|
||||
if (!sle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
// Deduct the fee, so it's not available during the transaction.
|
||||
// Will only write the account back if the transaction succeeds.
|
||||
sle->setFieldAmount(sfBalance, sle->getFieldAmount(sfBalance) - feePaid);
|
||||
if (feePayer != accountID_)
|
||||
view().update(sle); // done in `apply()` for the account
|
||||
if (feePaid == beast::kZero)
|
||||
return tesSUCCESS;
|
||||
|
||||
XRPAmount balance = beast::kZero;
|
||||
if (sle->isFieldPresent(feePayer.balanceField))
|
||||
{
|
||||
balance = sle->getFieldAmount(feePayer.balanceField).xrp();
|
||||
}
|
||||
else if (feePayer.balanceField != sfFeeAmount)
|
||||
{
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// A co-signed sponsor pays the fee out of its own account balance, but must
|
||||
// never be charged into its account reserve, and a pre-funded sponsorship's
|
||||
// fee is capped by sfMaxFee. Mirror the spendable amount computed in
|
||||
// checkFee() so both limits are enforced on the apply path too.
|
||||
XRPAmount spendable = balance;
|
||||
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
||||
{
|
||||
auto const sponsorReserve = accountReserve(view(), sle, j_);
|
||||
// max(balance - reserve, 0) with overflow handling
|
||||
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
|
||||
}
|
||||
else if (feePayer.type == FeePayerType::SponsorPreFunded && sle->isFieldPresent(sfMaxFee))
|
||||
{
|
||||
auto const cap = sle->getFieldAmount(sfMaxFee).xrp();
|
||||
spendable = std::min(spendable, cap);
|
||||
}
|
||||
|
||||
// Only sponsor fee-payers reject here on insufficient funds. For an
|
||||
// ordinary account, the fee falls through and is capped by reset(), which
|
||||
// caps to the account's balance. That capping is wrong for sponsors: a
|
||||
// co-signed sponsor would be charged into its own reserve, and a prefunded
|
||||
// sponsorship's fee amount should be rejected rather than partially spent.
|
||||
if (feePaid > spendable &&
|
||||
(feePayer.type == FeePayerType::SponsorPreFunded ||
|
||||
feePayer.type == FeePayerType::SponsorCoSigned))
|
||||
{
|
||||
if ((spendable > beast::kZero) && !view().open())
|
||||
return tecINSUFF_FEE;
|
||||
|
||||
return terINSUF_FEE_B;
|
||||
}
|
||||
|
||||
auto const feeAmountAfter = balance - feePaid;
|
||||
|
||||
if (feeAmountAfter == beast::kZero && feePayer.balanceField == sfFeeAmount)
|
||||
{
|
||||
// Because ltSponsorship.sfFeeAmount is soeOptional
|
||||
sle->makeFieldAbsent(feePayer.balanceField);
|
||||
}
|
||||
else
|
||||
{
|
||||
sle->setFieldAmount(feePayer.balanceField, feeAmountAfter);
|
||||
}
|
||||
|
||||
view().update(sle);
|
||||
|
||||
// VFALCO Should we call view().rawDestroyXRP() here as well?
|
||||
return tesSUCCESS;
|
||||
@@ -656,7 +855,7 @@ Transactor::ticketDelete(
|
||||
}
|
||||
|
||||
// Update the Ticket owner's reserve.
|
||||
adjustOwnerCount(view, sleAccount, -1, j);
|
||||
decreaseOwnerCountForObject(view, sleAccount, sleTicket, 1, j);
|
||||
|
||||
// Remove Ticket from ledger.
|
||||
view.erase(sleTicket);
|
||||
@@ -750,6 +949,21 @@ Transactor::checkSign(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
if (sigObject.isFieldPresent(sfSponsorSignature))
|
||||
{
|
||||
// Co-signed sponsorship
|
||||
|
||||
// Sanity check: already checked in preflight1
|
||||
if (!sigObject.isFieldPresent(sfSponsor))
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sponsorID = sigObject.getAccountID(sfSponsor);
|
||||
auto const sponsorSignature = sigObject.getFieldObject(sfSponsorSignature);
|
||||
if (auto const ret = checkSign(view, flags, std::nullopt, sponsorID, sponsorSignature, j);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If the pk is empty and not simulate or simulate and signers,
|
||||
// then we must be multi-signing.
|
||||
if (sigObject.isFieldPresent(sfSigners))
|
||||
@@ -1079,11 +1293,38 @@ Transactor::reset(XRPAmount fee)
|
||||
if (!txnAcct)
|
||||
return {tefINTERNAL, beast::kZero};
|
||||
|
||||
auto const payerSle = view().peek(keylet::account(ctx_.tx.getFeePayer()));
|
||||
auto const feePayer = getFeePayer(view(), ctx_.tx);
|
||||
auto const payerSle = view().peek(feePayer.keylet);
|
||||
|
||||
if (!payerSle)
|
||||
return {tefINTERNAL, beast::kZero}; // LCOV_EXCL_LINE
|
||||
|
||||
auto const balance = payerSle->getFieldAmount(sfBalance).xrp();
|
||||
XRPAmount balance = beast::kZero;
|
||||
if (payerSle->isFieldPresent(feePayer.balanceField))
|
||||
{
|
||||
balance = payerSle->getFieldAmount(feePayer.balanceField).xrp();
|
||||
}
|
||||
else if (feePayer.balanceField != sfFeeAmount)
|
||||
{
|
||||
return {tefINTERNAL, beast::kZero}; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (feePayer.type == FeePayerType::SponsorPreFunded && payerSle->isFieldPresent(sfMaxFee))
|
||||
{
|
||||
auto const cap = payerSle->getFieldAmount(sfMaxFee).xrp();
|
||||
fee = std::min(fee, cap);
|
||||
}
|
||||
|
||||
// A co-signed sponsor must never be charged into its own account reserve,
|
||||
// so the fee is capped to the balance above the reserve rather than to the
|
||||
// full balance.
|
||||
XRPAmount spendable = balance;
|
||||
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
||||
{
|
||||
auto const sponsorReserve = accountReserve(view(), payerSle, j_);
|
||||
// max(balance - reserve, 0) with overflow handling
|
||||
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
|
||||
}
|
||||
|
||||
// balance should have already been checked in checkFee / preFlight.
|
||||
XRPL_ASSERT(
|
||||
@@ -1093,8 +1334,8 @@ Transactor::reset(XRPAmount fee)
|
||||
// We retry/reject the transaction if the account balance is zero or
|
||||
// we're applying against an open ledger and the balance is less than
|
||||
// the fee
|
||||
if (fee > balance)
|
||||
fee = balance;
|
||||
if (fee > spendable)
|
||||
fee = spendable;
|
||||
|
||||
// Since we reset the context, we need to charge the fee and update
|
||||
// the account's sequence number (or consume the Ticket) again.
|
||||
@@ -1102,7 +1343,17 @@ Transactor::reset(XRPAmount fee)
|
||||
// If for some reason we are unable to consume the ticket or sequence
|
||||
// then the ledger is corrupted. Rather than make things worse we
|
||||
// reject the transaction.
|
||||
payerSle->setFieldAmount(sfBalance, balance - fee);
|
||||
auto const feeAmountAfter = balance - fee;
|
||||
if (feeAmountAfter == beast::kZero && feePayer.balanceField == sfFeeAmount)
|
||||
{
|
||||
// Because ltSponsorship.sfFeeAmount is soeOptional
|
||||
payerSle->makeFieldAbsent(feePayer.balanceField);
|
||||
}
|
||||
else
|
||||
{
|
||||
payerSle->setFieldAmount(feePayer.balanceField, feeAmountAfter);
|
||||
}
|
||||
|
||||
TER const ter{consumeSeqProxy(txnAcct)};
|
||||
XRPL_ASSERT(isTesSuccess(ter), "xrpl::Transactor::reset : result is tesSUCCESS");
|
||||
|
||||
@@ -1116,6 +1367,48 @@ Transactor::reset(XRPAmount fee)
|
||||
return {ter, fee};
|
||||
}
|
||||
|
||||
FeePayer
|
||||
Transactor::getFeePayer(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
if (tx.isFieldPresent(sfSponsor) && isFeeSponsored(tx))
|
||||
{
|
||||
auto const sponsorID = tx.getAccountID(sfSponsor);
|
||||
auto const sponseeID = tx.getInitiator();
|
||||
auto const sponsorshipKeylet = keylet::sponsorship(sponsorID, sponseeID);
|
||||
|
||||
// if pre-funded sponsorship exists, prefer it
|
||||
if (view.exists(sponsorshipKeylet))
|
||||
{
|
||||
// pre funded
|
||||
return FeePayer{
|
||||
.id = sponsorID,
|
||||
.keylet = sponsorshipKeylet,
|
||||
.balanceField = sfFeeAmount,
|
||||
.type = FeePayerType::SponsorPreFunded};
|
||||
}
|
||||
|
||||
// Checked in Transactor::checkSponsor
|
||||
XRPL_ASSERT(
|
||||
tx.isFieldPresent(sfSponsorSignature),
|
||||
"xrpl::getFeePayer has sponsor signature without a sponsorship object");
|
||||
|
||||
// co-signed
|
||||
return FeePayer{
|
||||
.id = sponsorID,
|
||||
.keylet = keylet::account(sponsorID),
|
||||
.balanceField = sfBalance,
|
||||
.type = FeePayerType::SponsorCoSigned};
|
||||
}
|
||||
|
||||
AccountID const payerID = tx.getInitiator();
|
||||
auto const payerAccountKeylet = keylet::account(payerID);
|
||||
auto const payerType =
|
||||
tx.isFieldPresent(sfDelegate) ? FeePayerType::Delegate : FeePayerType::Account;
|
||||
|
||||
return FeePayer{
|
||||
.id = payerID, .keylet = payerAccountKeylet, .balanceField = sfBalance, .type = payerType};
|
||||
}
|
||||
|
||||
// The sole purpose of this function is to provide a convenient, named
|
||||
// location to set a breakpoint, to be used when replaying transactions.
|
||||
void
|
||||
|
||||
@@ -181,6 +181,9 @@ invokePreclaim(PreclaimContext const& ctx)
|
||||
if (NotTEC const result = T::checkPriorTxAndLastLedger(ctx))
|
||||
return result;
|
||||
|
||||
if (NotTEC const result = T::checkSponsor(ctx.view, ctx.tx))
|
||||
return result;
|
||||
|
||||
if (NotTEC const result =
|
||||
Transactor::invokeCheckPermission<T>(ctx.view, ctx.tx))
|
||||
return result;
|
||||
|
||||
@@ -148,6 +148,15 @@ XRPNotCreated::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref a
|
||||
if (isXRP((*before)[sfAmount]))
|
||||
drops_ -= (*before)[sfAmount].xrp().drops();
|
||||
break;
|
||||
case ltSPONSORSHIP:
|
||||
if (before->isFieldPresent(sfFeeAmount))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
isXRP((*before)[sfFeeAmount]),
|
||||
"XRPNotCreated::visitEntry : Sponsorship.FeeAmount is XRP");
|
||||
drops_ -= (*before)[sfFeeAmount].xrp().drops();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -168,6 +177,15 @@ XRPNotCreated::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref a
|
||||
if (!isDelete && isXRP((*after)[sfAmount]))
|
||||
drops_ += (*after)[sfAmount].xrp().drops();
|
||||
break;
|
||||
case ltSPONSORSHIP:
|
||||
if (!isDelete && after->isFieldPresent(sfFeeAmount))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
isXRP((*after)[sfFeeAmount]),
|
||||
"XRPNotCreated::visitEntry : Sponsorship.FeeAmount is XRP");
|
||||
drops_ += (*after)[sfFeeAmount].xrp().drops();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -515,6 +533,20 @@ AccountRootsDeletedClean::finalize(
|
||||
if (enforce)
|
||||
return false;
|
||||
}
|
||||
// An account should not be deleted with sponsorship fields
|
||||
if (after->isFieldPresent(sfSponsoredOwnerCount) ||
|
||||
after->isFieldPresent(sfSponsoringOwnerCount) ||
|
||||
after->isFieldPresent(sfSponsoringAccountCount) || after->isFieldPresent(sfSponsor))
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: account deletion left "
|
||||
"behind a sponsorship field";
|
||||
XRPL_ASSERT(
|
||||
enforce,
|
||||
"xrpl::AccountRootsDeletedClean::finalize : "
|
||||
"deleted account has no sponsorship fields");
|
||||
if (enforce)
|
||||
return false;
|
||||
}
|
||||
// Simple types
|
||||
for (auto const& [keyletfunc, _1, _2] : kDirectAccountKeylets)
|
||||
{
|
||||
@@ -881,8 +913,10 @@ ValidPseudoAccounts::visitEntry(bool isDelete, SLE::const_ref before, SLE::const
|
||||
// 1. Exactly one of the pseudo-account fields is set.
|
||||
// 2. The sequence number is not changed.
|
||||
// 3. The lsfDisableMaster, lsfDefaultRipple, and lsfDepositAuth
|
||||
// flags are set.
|
||||
// flags are set.
|
||||
// 4. The RegularKey is not set.
|
||||
// 5. The SponsoredOwnerCount, SponsoringOwnerCount, SponsoringAccountCount, Sponsor
|
||||
// fields are not set.
|
||||
{
|
||||
std::vector<SField const*> const& fields = getPseudoAccountFields();
|
||||
|
||||
@@ -908,6 +942,12 @@ ValidPseudoAccounts::visitEntry(bool isDelete, SLE::const_ref before, SLE::const
|
||||
{
|
||||
errors_.emplace_back("pseudo-account has a regular key");
|
||||
}
|
||||
if (after->isFieldPresent(sfSponsoredOwnerCount) ||
|
||||
after->isFieldPresent(sfSponsoringOwnerCount) || after->isFieldPresent(sfSponsor) ||
|
||||
after->isFieldPresent(sfSponsoringAccountCount))
|
||||
{
|
||||
errors_.emplace_back("pseudo-account has a sponsorship field");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
158
src/libxrpl/tx/invariants/SponsorshipInvariant.cpp
Normal file
158
src/libxrpl/tx/invariants/SponsorshipInvariant.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <xrpl/tx/invariants/SponsorshipInvariant.h>
|
||||
//
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Add new sponsorship-related invariants implementations
|
||||
void
|
||||
SponsorshipOwnerCountsMatch::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after)
|
||||
{
|
||||
auto getSponsored = [](SLE::const_ref sle) -> std::uint32_t {
|
||||
if (sle && sle->getType() == ltACCOUNT_ROOT)
|
||||
return sle->getFieldU32(sfSponsoredOwnerCount);
|
||||
return 0;
|
||||
};
|
||||
auto getSponsoring = [](SLE::const_ref sle) -> std::uint32_t {
|
||||
if (sle && sle->getType() == ltACCOUNT_ROOT)
|
||||
return sle->getFieldU32(sfSponsoringOwnerCount);
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto getOwnerCount = [](SLE::const_ref sle) -> std::uint32_t {
|
||||
if (sle && sle->getType() == ltACCOUNT_ROOT)
|
||||
return sle->getFieldU32(sfOwnerCount);
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto getSponsoredObjectOwnerCount = [&](SLE::const_ref sle) -> std::uint32_t {
|
||||
if (!sle)
|
||||
return 0;
|
||||
switch (sle->getType())
|
||||
{
|
||||
case ltACCOUNT_ROOT:
|
||||
return 0;
|
||||
case ltRIPPLE_STATE: {
|
||||
// A trust line can be reserve-sponsored independently on each
|
||||
// side, so it may contribute up to two sponsored owner counts.
|
||||
uint32_t ownerCount = 0;
|
||||
if (sle->isFieldPresent(sfHighSponsor))
|
||||
ownerCount++;
|
||||
if (sle->isFieldPresent(sfLowSponsor))
|
||||
ownerCount++;
|
||||
return ownerCount;
|
||||
}
|
||||
default:
|
||||
// Every other supported type carries a single sfSponsor field
|
||||
// and contributes its full owner-count magnitude only when it is
|
||||
// sponsored.
|
||||
if (!sle->isFieldPresent(sfSponsor))
|
||||
return 0;
|
||||
return getLedgerEntryOwnerCount(*sle);
|
||||
}
|
||||
};
|
||||
|
||||
// The values are implicitly casted to std::int64_t to calculate deltas.
|
||||
std::int64_t const beforeSponsored = getSponsored(before);
|
||||
std::int64_t const afterSponsored = getSponsored(after);
|
||||
std::int64_t const beforeSponsoring = getSponsoring(before);
|
||||
std::int64_t const afterSponsoring = getSponsoring(after);
|
||||
|
||||
std::int64_t const beforeSponsoredObjectOwnerCount = getSponsoredObjectOwnerCount(before);
|
||||
std::int64_t const afterSponsoredObjectOwnerCount =
|
||||
isDelete ? 0 : getSponsoredObjectOwnerCount(after);
|
||||
|
||||
deltaSponsoredOwnerCount_ += (afterSponsored - beforeSponsored);
|
||||
deltaSponsoringOwnerCount_ += (afterSponsoring - beforeSponsoring);
|
||||
|
||||
deltaSponsoredObjectOwnerCount_ +=
|
||||
(afterSponsoredObjectOwnerCount - beforeSponsoredObjectOwnerCount);
|
||||
|
||||
if (getOwnerCount(after) < getSponsored(after))
|
||||
ownerCountBelowSponsored_ += 1;
|
||||
}
|
||||
|
||||
bool
|
||||
SponsorshipOwnerCountsMatch::finalize(
|
||||
STTx const&,
|
||||
TER const,
|
||||
XRPAmount const,
|
||||
ReadView const&,
|
||||
beast::Journal const& j) const
|
||||
{
|
||||
if (deltaSponsoredOwnerCount_ != deltaSponsoringOwnerCount_)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: SponsoredOwnerCount does not "
|
||||
"equal SponsoringOwnerCount delta.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ownerCountBelowSponsored_ > 0)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: OwnerCount must be greater than or equal to SponsoredOwnerCount.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deltaSponsoredObjectOwnerCount_ != deltaSponsoredOwnerCount_)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: SponsoredObjectOwnerCount does not "
|
||||
"equal SponsoredOwnerCount delta.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SponsorshipAccountCountMatchesField::visitEntry(bool, SLE::const_ref before, SLE::const_ref after)
|
||||
{
|
||||
auto getSponsoringAccountCount = [](SLE::const_ref sle) -> std::uint32_t {
|
||||
if (sle && sle->getType() == ltACCOUNT_ROOT)
|
||||
return sle->getFieldU32(sfSponsoringAccountCount);
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto hasSponsorField = [](SLE::const_ref sle) -> bool {
|
||||
return sle && sle->getType() == ltACCOUNT_ROOT && sle->isFieldPresent(sfSponsor);
|
||||
};
|
||||
|
||||
std::int64_t const beforeCount = getSponsoringAccountCount(before);
|
||||
std::int64_t const afterCount = getSponsoringAccountCount(after);
|
||||
deltaSponsoringAccountCount_ += (afterCount - beforeCount);
|
||||
|
||||
int const beforePresent = hasSponsorField(before) ? 1 : 0;
|
||||
int const afterPresent = hasSponsorField(after) ? 1 : 0;
|
||||
deltaSponsorFieldPresence_ += (afterPresent - beforePresent);
|
||||
}
|
||||
|
||||
bool
|
||||
SponsorshipAccountCountMatchesField::finalize(
|
||||
STTx const&,
|
||||
TER const,
|
||||
XRPAmount const,
|
||||
ReadView const&,
|
||||
beast::Journal const& j) const
|
||||
{
|
||||
if (deltaSponsoringAccountCount_ != deltaSponsorFieldPresence_)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: Net delta of SponsoringAccountCount does not "
|
||||
"match net delta of sfSponsor presence.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -222,7 +222,10 @@ ValidVault::deltaAssetsTxAccount(STTx const& tx, XRPAmount fee) const
|
||||
if (!ret.has_value() || !vaultAsset.native())
|
||||
return ret;
|
||||
|
||||
if (auto const delegate = tx[~sfDelegate]; delegate.has_value() && *delegate != tx[sfAccount])
|
||||
// Only add the fee back if tx[sfAccount] actually paid it. When the fee is
|
||||
// paid by someone else (a delegate or a fee sponsor), the
|
||||
// account's XRP balance moved only by the vault amount.
|
||||
if (tx.getFeePayerID() != tx[sfAccount])
|
||||
return ret;
|
||||
|
||||
ret->delta += fee.drops();
|
||||
@@ -1044,10 +1047,8 @@ ValidVault::finalize(
|
||||
|
||||
case ttLOAN_SET:
|
||||
case ttLOAN_MANAGE:
|
||||
case ttLOAN_PAY: {
|
||||
// TBD
|
||||
case ttLOAN_PAY:
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
// LCOV_EXCL_START
|
||||
|
||||
@@ -731,7 +731,7 @@ BookStep<TIn, TOut, TDerived>::forEachOffer(
|
||||
// Create MPToken for the offer's owner. No need to check
|
||||
// for the reserve since the offer is removed if it is consumed.
|
||||
// Therefore, the owner count remains the same.
|
||||
if (auto const err = checkCreateMPT(sb, assetIn.get<MPTIssue>(), owner, j_);
|
||||
if (auto const err = checkCreateMPT(sb, assetIn.get<MPTIssue>(), owner, {}, j_);
|
||||
!isTesSuccess(err))
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -410,7 +410,8 @@ MPTEndpointOfferCrossingStep::checkCreateMPT(ApplyView& view, xrpl::DebtDirectio
|
||||
// for the reserve since the offer doesn't go on the books
|
||||
// if crossed. Insufficient reserve is allowed if the offer
|
||||
// crossed. See CreateOffer::applyGuts() for reserve check.
|
||||
if (auto const err = xrpl::checkCreateMPT(view, mptIssue_, dst_, j_); !isTesSuccess(err))
|
||||
if (auto const err = xrpl::checkCreateMPT(view, mptIssue_, dst_, {}, j_);
|
||||
!isTesSuccess(err))
|
||||
{
|
||||
JLOG(j_.trace()) << "MPTEndpointStep::checkCreateMPT: failed create MPT";
|
||||
resetCache(srcDebtDir);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
bool
|
||||
AccountDelete::checkExtraFeatures(PreflightContext const& ctx)
|
||||
{
|
||||
@@ -268,6 +267,15 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
|
||||
if (cp)
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
if (sleAccount->isFieldPresent(sfSponsor))
|
||||
{
|
||||
if (dst != sleAccount->getAccountID(sfSponsor))
|
||||
return tecNO_SPONSOR_PERMISSION;
|
||||
}
|
||||
if (sleAccount->isFieldPresent(sfSponsoringOwnerCount) ||
|
||||
sleAccount->isFieldPresent(sfSponsoringAccountCount))
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
// We don't allow an account to be deleted if its sequence number
|
||||
// is within 256 of the current ledger. This prevents replay of old
|
||||
// transactions if this account is resurrected after it is deleted.
|
||||
@@ -394,6 +402,35 @@ AccountDelete::doApply()
|
||||
(*src)[sfBalance] = (*src)[sfBalance] - remainingBalance;
|
||||
ctx_.deliver(remainingBalance);
|
||||
|
||||
if (src->isFieldPresent(sfSponsor))
|
||||
{
|
||||
auto const sponsorID = src->getAccountID(sfSponsor);
|
||||
auto sponsorSle = view().peek(keylet::account(sponsorID));
|
||||
|
||||
if (!sponsorSle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const sponsoringAccountCount = sponsorSle->getFieldU32(sfSponsoringAccountCount);
|
||||
|
||||
XRPL_ASSERT(
|
||||
sponsoringAccountCount != 0,
|
||||
"xrpl::AccountDelete::doApply : sponsoring account count is present");
|
||||
if (sponsoringAccountCount == 0)
|
||||
{
|
||||
// sanity check
|
||||
// Since sfSponsoringAccountCount is set to soeDEFAULT, the field will not be
|
||||
// present with a value of 0.
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
sponsorSle->at(sfSponsoringAccountCount) = sponsoringAccountCount - 1;
|
||||
view().update(sponsorSle);
|
||||
|
||||
// Following line might look redundant, but without it, sfSponsor
|
||||
// would end up remaining in after-ltAccountRoot during the
|
||||
// InvariantCheck.
|
||||
src->makeFieldAbsent(sfSponsor);
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
(*src)[sfBalance] == XRPAmount(0), "xrpl::AccountDelete::doApply : source balance is zero");
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -147,9 +148,7 @@ SignerListSet::preCompute()
|
||||
Transactor::preCompute();
|
||||
}
|
||||
|
||||
// The return type is signed so it is compatible with the 3rd argument
|
||||
// of adjustOwnerCount() (which must be signed).
|
||||
static int
|
||||
static std::uint32_t
|
||||
signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules)
|
||||
{
|
||||
// We always compute the full change in OwnerCount, taking into account:
|
||||
@@ -165,7 +164,7 @@ signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules)
|
||||
// units. A SignerList with 8 entries would cost 10 OwnerCount units.
|
||||
//
|
||||
// The static_cast should always be safe since entryCount should always
|
||||
// be in the range from 1 to 32.
|
||||
// be in the range from 1 to 32, so the result is always positive.
|
||||
// We've got a lot of room to grow.
|
||||
XRPL_ASSERT(
|
||||
entryCount >= STTx::kMinMultiSigners,
|
||||
@@ -196,12 +195,11 @@ removeSignersFromLedger(
|
||||
// There are two different ways that the OwnerCount could be managed.
|
||||
// If the lsfOneOwnerCount bit is set then remove just one owner count.
|
||||
// Otherwise use the pre-MultiSignReserve amendment calculation.
|
||||
int removeFromOwnerCount = -1;
|
||||
std::uint32_t removeFromOwnerCount = 1;
|
||||
if (!signers->isFlag(lsfOneOwnerCount))
|
||||
{
|
||||
STArray const& actualList = signers->getFieldArray(sfSignerEntries);
|
||||
removeFromOwnerCount =
|
||||
signerCountBasedOwnerCountDelta(actualList.size(), view.rules()) * -1;
|
||||
removeFromOwnerCount = signerCountBasedOwnerCountDelta(actualList.size(), view.rules());
|
||||
}
|
||||
|
||||
// Remove the node from the account directory.
|
||||
@@ -215,8 +213,8 @@ removeSignersFromLedger(
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
adjustOwnerCount(
|
||||
view, view.peek(accountKeylet), removeFromOwnerCount, registry.getJournal("View"));
|
||||
decreaseOwnerCountForObject(
|
||||
view, view.peek(accountKeylet), signers, removeFromOwnerCount, registry.getJournal("View"));
|
||||
|
||||
view.erase(signers);
|
||||
|
||||
@@ -315,19 +313,20 @@ SignerListSet::replaceSignerList()
|
||||
if (!sle)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
// Compute new reserve. Verify the account has funds to meet the reserve.
|
||||
std::uint32_t const oldOwnerCount{(*sle)[sfOwnerCount]};
|
||||
|
||||
static constexpr int kAddedOwnerCount = 1;
|
||||
std::uint32_t const flags{lsfOneOwnerCount};
|
||||
|
||||
XRPAmount const newReserve{view().fees().accountReserve(oldOwnerCount + kAddedOwnerCount)};
|
||||
|
||||
// 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 TicketCreate.
|
||||
if (preFeeBalance_ < newReserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
if (auto const ret = checkReserve(
|
||||
ctx_.getApplyViewContext(),
|
||||
sle,
|
||||
preFeeBalance_,
|
||||
{.ownerCountDelta = kAddedOwnerCount},
|
||||
ctx_.journal);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Everything's ducky. Add the ltSIGNER_LIST to the ledger.
|
||||
auto signerList = std::make_shared<SLE>(signerListKeylet);
|
||||
@@ -349,7 +348,8 @@ SignerListSet::replaceSignerList()
|
||||
|
||||
// If we succeeded, the new entry counts against the
|
||||
// creator's reserve.
|
||||
adjustOwnerCount(view(), sle, kAddedOwnerCount, viewJ);
|
||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, kAddedOwnerCount, viewJ);
|
||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), signerList);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -91,8 +91,7 @@ CheckCancel::doApply()
|
||||
}
|
||||
|
||||
// If we succeeded, update the check owner's reserve.
|
||||
auto const sleSrc = view().peek(keylet::account(srcId));
|
||||
adjustOwnerCount(view(), sleSrc, -1, viewJ);
|
||||
decreaseOwnerCountForObject(view(), srcId, sleCheck, 1, viewJ);
|
||||
|
||||
// Remove check from ledger.
|
||||
view().erase(sleCheck);
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/scope.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/PaymentSandbox.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
@@ -30,7 +32,7 @@
|
||||
#include <xrpl/tx/paths/detail/Steps.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -175,7 +177,7 @@ CheckCash::preclaim(PreclaimContext const& ctx)
|
||||
// once the check is cashed, since the check's reserve will no
|
||||
// longer be required. So, if we're dealing in XRP, we add one
|
||||
// reserve's worth to the available funds.
|
||||
if (value.native())
|
||||
if (value.native() && !sleCheck->isFieldPresent(sfSponsor))
|
||||
availableFunds += XRPAmount{ctx.view.fees().increment};
|
||||
|
||||
if (value > availableFunds)
|
||||
@@ -307,6 +309,8 @@ CheckCash::doApply()
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const sponsorCheckSle = getLedgerEntryReserveSponsor(psb, sleCheck);
|
||||
|
||||
// Preclaim already checked that source has at least the requested
|
||||
// funds.
|
||||
//
|
||||
@@ -335,7 +339,7 @@ CheckCash::doApply()
|
||||
// from src's directory, we allow them to send that additional
|
||||
// incremental reserve amount in the transfer. Hence the -1
|
||||
// argument.
|
||||
STAmount const srcLiquid{xrpLiquid(psb, srcId, -1, viewJ)};
|
||||
STAmount const srcLiquid{xrpLiquid(psb, srcId, sponsorCheckSle ? 0 : -1, viewJ)};
|
||||
|
||||
// Now, how much do they need in order to be successful?
|
||||
STAmount const xrpDeliver{
|
||||
@@ -385,14 +389,25 @@ CheckCash::doApply()
|
||||
STAmount const flowDeliver{
|
||||
optDeliverMin ? maxDeliverMin() : ctx_.tx.getFieldAmount(sfAmount)};
|
||||
|
||||
auto applyViewContext = ApplyViewContext({.view = psb, .tx = ctx_.tx});
|
||||
auto const sponsorSle = getTxReserveSponsor(applyViewContext);
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
// Check reserve. Return destination account SLE if enough reserve,
|
||||
// otherwise return nullptr.
|
||||
auto checkReserve = [&]() -> SLE::pointer {
|
||||
auto checkDstReserve = [&]() -> SLE::pointer {
|
||||
auto sleDst = psb.peek(keylet::account(accountID_));
|
||||
|
||||
// Can the account cover the trust line's or MPT reserve?
|
||||
if (std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
|
||||
preFeeBalance_ < psb.fees().accountReserve(ownerCount + 1))
|
||||
if (auto const ret = checkReserve(
|
||||
applyViewContext,
|
||||
sleDst,
|
||||
preFeeBalance_,
|
||||
*sponsorSle,
|
||||
{.ownerCountDelta = 1},
|
||||
j_);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
JLOG(j_.trace()) << "Trust line does not exist. "
|
||||
"Insufficient reserve to create line.";
|
||||
@@ -426,7 +441,7 @@ CheckCash::doApply()
|
||||
// a. this (destination) account and
|
||||
// b. issuing account (not sending account).
|
||||
|
||||
auto const sleDst = checkReserve();
|
||||
auto const sleDst = checkDstReserve();
|
||||
if (sleDst == nullptr)
|
||||
return tecNO_LINE_INSUF_RESERVE;
|
||||
|
||||
@@ -449,6 +464,7 @@ CheckCash::doApply()
|
||||
Issue(currency, accountID_), // limit of zero
|
||||
0, // quality in
|
||||
0, // quality out
|
||||
*sponsorSle, // sponsor
|
||||
viewJ); // journal
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
@@ -491,11 +507,12 @@ CheckCash::doApply()
|
||||
auto const mptokenKey = keylet::mptoken(mptID, accountID_);
|
||||
if (!psb.exists(mptokenKey))
|
||||
{
|
||||
auto sleDst = checkReserve();
|
||||
auto sleDst = checkDstReserve();
|
||||
if (sleDst == nullptr)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
if (auto const err = checkCreateMPT(psb, mptID, accountID_, j_);
|
||||
if (auto const err =
|
||||
checkCreateMPT(psb, mptID, accountID_, *sponsorSle, j_);
|
||||
!isTesSuccess(err))
|
||||
{
|
||||
return err;
|
||||
@@ -581,7 +598,7 @@ CheckCash::doApply()
|
||||
}
|
||||
|
||||
// If we succeeded, update the check owner's reserve.
|
||||
adjustOwnerCount(psb, psb.peek(keylet::account(srcId)), -1, viewJ);
|
||||
decreaseOwnerCountForObject(psb, srcId, sleCheck, 1, viewJ);
|
||||
|
||||
// Remove check from ledger.
|
||||
psb.erase(sleCheck);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
@@ -194,13 +195,10 @@ CheckCreate::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 (preFeeBalance_ < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
if (auto const ret = checkReserve(
|
||||
ctx_.getApplyViewContext(), sle, preFeeBalance_, {.ownerCountDelta = 1}, ctx_.journal);
|
||||
!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.
|
||||
std::uint32_t const seq = ctx_.tx.getSeqValue();
|
||||
@@ -253,7 +251,9 @@ CheckCreate::doApply()
|
||||
sleCheck->setFieldU64(sfOwnerNode, *page);
|
||||
}
|
||||
// If we succeeded, the new entry counts against the creator's reserve.
|
||||
adjustOwnerCount(view(), sle, 1, viewJ);
|
||||
|
||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, viewJ);
|
||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCheck);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user