From 697fb64e8c833d189f7dbd1a12fdeea5b0327d6a Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Wed, 18 Mar 2026 17:46:27 +0000 Subject: [PATCH 01/16] ci: Don't check PR title for drafts (#6573) --- .github/workflows/check-pr-title.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-pr-title.yml b/.github/workflows/check-pr-title.yml index a524d759b5..b88816cfea 100644 --- a/.github/workflows/check-pr-title.yml +++ b/.github/workflows/check-pr-title.yml @@ -5,9 +5,10 @@ on: types: - checks_requested pull_request: - types: [opened, edited, reopened, synchronize] + types: [opened, edited, reopened, synchronize, ready_for_review] branches: [develop] jobs: check_title: + if: ${{ github.event.pull_request.draft != true }} uses: XRPLF/actions/.github/workflows/check-pr-title.yml@c6311685db43aa07971c4a6764320fecbc2acdcd From 804a351773c1d28eead4377227cac5e4420d475b Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Wed, 18 Mar 2026 18:31:42 +0000 Subject: [PATCH 02/16] ci: Use external action implementation of check-pr-title (#6578) --- .github/workflows/check-pr-title.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-pr-title.yml b/.github/workflows/check-pr-title.yml index b88816cfea..1181ca586f 100644 --- a/.github/workflows/check-pr-title.yml +++ b/.github/workflows/check-pr-title.yml @@ -11,4 +11,4 @@ on: jobs: check_title: if: ${{ github.event.pull_request.draft != true }} - uses: XRPLF/actions/.github/workflows/check-pr-title.yml@c6311685db43aa07971c4a6764320fecbc2acdcd + uses: XRPLF/actions/.github/workflows/check-pr-title.yml@f9c2b57a7ac30d70555b5de6e627005f62e933f3 From d360e7c5b6aadfe87454bab43d0a6668f9d00455 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 18 Mar 2026 15:52:07 -0400 Subject: [PATCH 03/16] refactor: Rename transactor files/classes to match the tx name (#6580) --- .../xrpl/protocol/detail/transactions.macro | 30 ++++++++-------- include/xrpl/tx/Transactor.h | 2 +- .../{DeleteAccount.h => AccountDelete.h} | 6 ++-- .../account/{SetAccount.h => AccountSet.h} | 6 ++-- .../{SetSignerList.h => SignerListSet.h} | 10 +++--- .../check/{CashCheck.h => CheckCancel.h} | 6 ++-- .../check/{CreateCheck.h => CheckCash.h} | 6 ++-- .../check/{CancelCheck.h => CheckCreate.h} | 6 ++-- .../tx/transactors/delegate/DelegateSet.h | 2 +- .../dex/{CancelOffer.h => OfferCancel.h} | 6 ++-- .../dex/{CreateOffer.h => OfferCreate.h} | 6 ++-- .../oracle/{DeleteOracle.h => OracleDelete.h} | 8 ++--- .../oracle/{SetOracle.h => OracleSet.h} | 8 ++--- .../tx/transactors/payment/DepositPreauth.h | 2 +- .../{PayChanClaim.h => PaymentChannelClaim.h} | 6 ++-- ...PayChanCreate.h => PaymentChannelCreate.h} | 6 ++-- .../{PayChanFund.h => PaymentChannelFund.h} | 6 ++-- .../system/{CreateTicket.h => TicketCreate.h} | 8 ++--- .../token/{SetTrust.h => TrustSet.h} | 6 ++-- sanitizers/suppressions/ubsan.supp | 8 ++--- src/libxrpl/ledger/View.cpp | 4 +-- src/libxrpl/protocol/Indexes.cpp | 2 +- .../{DeleteAccount.cpp => AccountDelete.cpp} | 36 +++++++++---------- .../{SetAccount.cpp => AccountSet.cpp} | 18 +++++----- .../{SetSignerList.cpp => SignerListSet.cpp} | 34 +++++++++--------- .../{CancelCheck.cpp => CheckCancel.cpp} | 8 ++--- .../check/{CashCheck.cpp => CheckCash.cpp} | 8 ++--- .../{CreateCheck.cpp => CheckCreate.cpp} | 8 ++--- .../tx/transactors/dex/AMMWithdraw.cpp | 2 +- .../dex/{CancelOffer.cpp => OfferCancel.cpp} | 10 +++--- .../dex/{CreateOffer.cpp => OfferCreate.cpp} | 36 +++++++++---------- .../{DeleteOracle.cpp => OracleDelete.cpp} | 10 +++--- .../oracle/{SetOracle.cpp => OracleSet.cpp} | 8 ++--- .../tx/transactors/payment/DepositPreauth.cpp | 2 +- ...yChanClaim.cpp => PaymentChannelClaim.cpp} | 17 ++++----- ...hanCreate.cpp => PaymentChannelCreate.cpp} | 10 +++--- ...PayChanFund.cpp => PaymentChannelFund.cpp} | 10 +++--- ...nHelpers.cpp => PaymentChannelHelpers.cpp} | 2 +- ...yChanHelpers.h => PaymentChannelHelpers.h} | 0 .../{CreateTicket.cpp => TicketCreate.cpp} | 10 +++--- .../token/{SetTrust.cpp => TrustSet.cpp} | 14 ++++---- src/test/app/AMM_test.cpp | 6 ++-- src/test/app/AccountSet_test.cpp | 2 +- src/test/app/NFToken_test.cpp | 4 +-- src/test/app/Ticket_test.cpp | 2 +- .../{SetTrust_test.cpp => TrustSet_test.cpp} | 14 ++++---- src/xrpld/app/misc/detail/TxQ.cpp | 2 +- 47 files changed, 197 insertions(+), 226 deletions(-) rename include/xrpl/tx/transactors/account/{DeleteAccount.h => AccountDelete.h} (77%) rename include/xrpl/tx/transactors/account/{SetAccount.h => AccountSet.h} (82%) rename include/xrpl/tx/transactors/account/{SetSignerList.h => SignerListSet.h} (86%) rename include/xrpl/tx/transactors/check/{CashCheck.h => CheckCancel.h} (73%) rename include/xrpl/tx/transactors/check/{CreateCheck.h => CheckCash.h} (71%) rename include/xrpl/tx/transactors/check/{CancelCheck.h => CheckCreate.h} (71%) rename include/xrpl/tx/transactors/dex/{CancelOffer.h => OfferCancel.h} (73%) rename include/xrpl/tx/transactors/dex/{CreateOffer.h => OfferCreate.h} (93%) rename include/xrpl/tx/transactors/oracle/{DeleteOracle.h => OracleDelete.h} (79%) rename include/xrpl/tx/transactors/oracle/{SetOracle.h => OracleSet.h} (77%) rename include/xrpl/tx/transactors/payment_channel/{PayChanClaim.h => PaymentChannelClaim.h} (76%) rename include/xrpl/tx/transactors/payment_channel/{PayChanCreate.h => PaymentChannelCreate.h} (73%) rename include/xrpl/tx/transactors/payment_channel/{PayChanFund.h => PaymentChannelFund.h} (72%) rename include/xrpl/tx/transactors/system/{CreateTicket.h => TicketCreate.h} (91%) rename include/xrpl/tx/transactors/token/{SetTrust.h => TrustSet.h} (81%) rename src/libxrpl/tx/transactors/account/{DeleteAccount.cpp => AccountDelete.cpp} (91%) rename src/libxrpl/tx/transactors/account/{SetAccount.cpp => AccountSet.cpp} (97%) rename src/libxrpl/tx/transactors/account/{SetSignerList.cpp => SignerListSet.cpp} (93%) rename src/libxrpl/tx/transactors/check/{CancelCheck.cpp => CheckCancel.cpp} (94%) rename src/libxrpl/tx/transactors/check/{CashCheck.cpp => CheckCash.cpp} (99%) rename src/libxrpl/tx/transactors/check/{CreateCheck.cpp => CheckCreate.cpp} (97%) rename src/libxrpl/tx/transactors/dex/{CancelOffer.cpp => OfferCancel.cpp} (85%) rename src/libxrpl/tx/transactors/dex/{CreateOffer.cpp => OfferCreate.cpp} (97%) rename src/libxrpl/tx/transactors/oracle/{DeleteOracle.cpp => OracleDelete.cpp} (89%) rename src/libxrpl/tx/transactors/oracle/{SetOracle.cpp => OracleSet.cpp} (98%) rename src/libxrpl/tx/transactors/payment_channel/{PayChanClaim.cpp => PaymentChannelClaim.cpp} (90%) rename src/libxrpl/tx/transactors/payment_channel/{PayChanCreate.cpp => PaymentChannelCreate.cpp} (95%) rename src/libxrpl/tx/transactors/payment_channel/{PayChanFund.cpp => PaymentChannelFund.cpp} (89%) rename src/libxrpl/tx/transactors/payment_channel/{PayChanHelpers.cpp => PaymentChannelHelpers.cpp} (95%) rename src/libxrpl/tx/transactors/payment_channel/{PayChanHelpers.h => PaymentChannelHelpers.h} (100%) rename src/libxrpl/tx/transactors/system/{CreateTicket.cpp => TicketCreate.cpp} (94%) rename src/libxrpl/tx/transactors/token/{SetTrust.cpp => TrustSet.cpp} (98%) rename src/test/app/{SetTrust_test.cpp => TrustSet_test.cpp} (98%) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index c9d4376082..a2f3c1be43 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -76,7 +76,7 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, /** This transaction type adjusts various account settings. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttACCOUNT_SET, 3, AccountSet, Delegation::notDelegable, @@ -124,7 +124,7 @@ TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, /** This transaction type creates an offer to trade one asset for another. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, Delegation::delegable, @@ -140,7 +140,7 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, /** This transaction type cancels existing offers to trade one asset for another. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, Delegation::delegable, @@ -154,7 +154,7 @@ TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, /** This transaction type creates a new set of tickets. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, Delegation::delegable, @@ -170,7 +170,7 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, // The SignerEntries are optional because a SignerList is deleted by // setting the SignerQuorum to zero and omitting SignerEntries. #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, Delegation::notDelegable, @@ -183,7 +183,7 @@ TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, /** This transaction type creates a new unidirectional XRP payment channel. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, Delegation::delegable, @@ -200,7 +200,7 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, /** This transaction type funds an existing unidirectional XRP payment channel. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, Delegation::delegable, @@ -214,7 +214,7 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, /** This transaction type submits a claim against an existing unidirectional payment channel. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, Delegation::delegable, @@ -231,7 +231,7 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, /** This transaction type creates a new check. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, Delegation::delegable, @@ -247,7 +247,7 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, /** This transaction type cashes an existing check. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttCHECK_CASH, 17, CheckCash, Delegation::delegable, @@ -261,7 +261,7 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash, /** This transaction type cancels an existing check. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, Delegation::delegable, @@ -288,7 +288,7 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, /** This transaction type modifies a trustline between two accounts. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttTRUST_SET, 20, TrustSet, Delegation::delegable, @@ -302,7 +302,7 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet, /** This transaction type deletes an existing account. */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, Delegation::notDelegable, @@ -650,7 +650,7 @@ TRANSACTION(ttDID_DELETE, 50, DIDDelete, /** This transaction type creates an Oracle instance */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttORACLE_SET, 51, OracleSet, Delegation::delegable, @@ -667,7 +667,7 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet, /** This transaction type deletes an Oracle instance */ #if TRANSACTION_INCLUDE -# include +# include #endif TRANSACTION(ttORACLE_DELETE, 52, OracleDelete, Delegation::delegable, diff --git a/include/xrpl/tx/Transactor.h b/include/xrpl/tx/Transactor.h index 03cbd60a8e..8d816f60f8 100644 --- a/include/xrpl/tx/Transactor.h +++ b/include/xrpl/tx/Transactor.h @@ -209,7 +209,7 @@ public: checkPermission(ReadView const& view, STTx const& tx); ///////////////////////////////////////////////////// - // Interface used by DeleteAccount + // Interface used by AccountDelete static TER ticketDelete( ApplyView& view, diff --git a/include/xrpl/tx/transactors/account/DeleteAccount.h b/include/xrpl/tx/transactors/account/AccountDelete.h similarity index 77% rename from include/xrpl/tx/transactors/account/DeleteAccount.h rename to include/xrpl/tx/transactors/account/AccountDelete.h index f55888ee00..81a11152ed 100644 --- a/include/xrpl/tx/transactors/account/DeleteAccount.h +++ b/include/xrpl/tx/transactors/account/AccountDelete.h @@ -4,12 +4,12 @@ namespace xrpl { -class DeleteAccount : public Transactor +class AccountDelete : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Blocker}; - explicit DeleteAccount(ApplyContext& ctx) : Transactor(ctx) + explicit AccountDelete(ApplyContext& ctx) : Transactor(ctx) { } @@ -29,6 +29,4 @@ public: doApply() override; }; -using AccountDelete = DeleteAccount; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/account/SetAccount.h b/include/xrpl/tx/transactors/account/AccountSet.h similarity index 82% rename from include/xrpl/tx/transactors/account/SetAccount.h rename to include/xrpl/tx/transactors/account/AccountSet.h index 3abfcb43bb..0940ab0739 100644 --- a/include/xrpl/tx/transactors/account/SetAccount.h +++ b/include/xrpl/tx/transactors/account/AccountSet.h @@ -5,12 +5,12 @@ namespace xrpl { -class SetAccount : public Transactor +class AccountSet : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; - explicit SetAccount(ApplyContext& ctx) : Transactor(ctx) + explicit AccountSet(ApplyContext& ctx) : Transactor(ctx) { } @@ -33,6 +33,4 @@ public: doApply() override; }; -using AccountSet = SetAccount; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/account/SetSignerList.h b/include/xrpl/tx/transactors/account/SignerListSet.h similarity index 86% rename from include/xrpl/tx/transactors/account/SetSignerList.h rename to include/xrpl/tx/transactors/account/SignerListSet.h index 4c2489922d..2529f0d36c 100644 --- a/include/xrpl/tx/transactors/account/SetSignerList.h +++ b/include/xrpl/tx/transactors/account/SignerListSet.h @@ -11,10 +11,10 @@ namespace xrpl { /** -See the README.md for an overview of the SetSignerList transaction that +See the README.md for an overview of the SignerListSet transaction that this class implements. */ -class SetSignerList : public Transactor +class SignerListSet : public Transactor { private: // Values determined during preCompute for use later. @@ -26,7 +26,7 @@ private: public: static constexpr ConsequencesFactoryType ConsequencesFactory{Blocker}; - explicit SetSignerList(ApplyContext& ctx) : Transactor(ctx) + explicit SignerListSet(ApplyContext& ctx) : Transactor(ctx) { } @@ -41,7 +41,7 @@ public: void preCompute() override; - // Interface used by DeleteAccount + // Interface used by AccountDelete static TER removeFromLedger( ServiceRegistry& registry, @@ -70,6 +70,4 @@ private: writeSignersToSLE(SLE::pointer const& ledgerEntry, std::uint32_t flags) const; }; -using SignerListSet = SetSignerList; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/check/CashCheck.h b/include/xrpl/tx/transactors/check/CheckCancel.h similarity index 73% rename from include/xrpl/tx/transactors/check/CashCheck.h rename to include/xrpl/tx/transactors/check/CheckCancel.h index 138790cf34..f16c6d2827 100644 --- a/include/xrpl/tx/transactors/check/CashCheck.h +++ b/include/xrpl/tx/transactors/check/CheckCancel.h @@ -4,12 +4,12 @@ namespace xrpl { -class CashCheck : public Transactor +class CheckCancel : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit CashCheck(ApplyContext& ctx) : Transactor(ctx) + explicit CheckCancel(ApplyContext& ctx) : Transactor(ctx) { } @@ -23,6 +23,4 @@ public: doApply() override; }; -using CheckCash = CashCheck; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/check/CreateCheck.h b/include/xrpl/tx/transactors/check/CheckCash.h similarity index 71% rename from include/xrpl/tx/transactors/check/CreateCheck.h rename to include/xrpl/tx/transactors/check/CheckCash.h index 98950b68f2..c64d45061d 100644 --- a/include/xrpl/tx/transactors/check/CreateCheck.h +++ b/include/xrpl/tx/transactors/check/CheckCash.h @@ -4,12 +4,12 @@ namespace xrpl { -class CreateCheck : public Transactor +class CheckCash : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit CreateCheck(ApplyContext& ctx) : Transactor(ctx) + explicit CheckCash(ApplyContext& ctx) : Transactor(ctx) { } @@ -23,6 +23,4 @@ public: doApply() override; }; -using CheckCreate = CreateCheck; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/check/CancelCheck.h b/include/xrpl/tx/transactors/check/CheckCreate.h similarity index 71% rename from include/xrpl/tx/transactors/check/CancelCheck.h rename to include/xrpl/tx/transactors/check/CheckCreate.h index 8a0e42c7ca..2b5aa9123d 100644 --- a/include/xrpl/tx/transactors/check/CancelCheck.h +++ b/include/xrpl/tx/transactors/check/CheckCreate.h @@ -4,12 +4,12 @@ namespace xrpl { -class CancelCheck : public Transactor +class CheckCreate : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit CancelCheck(ApplyContext& ctx) : Transactor(ctx) + explicit CheckCreate(ApplyContext& ctx) : Transactor(ctx) { } @@ -23,6 +23,4 @@ public: doApply() override; }; -using CheckCancel = CancelCheck; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/delegate/DelegateSet.h b/include/xrpl/tx/transactors/delegate/DelegateSet.h index 452a6d8305..cc3a8fe4cb 100644 --- a/include/xrpl/tx/transactors/delegate/DelegateSet.h +++ b/include/xrpl/tx/transactors/delegate/DelegateSet.h @@ -22,7 +22,7 @@ public: TER doApply() override; - // Interface used by DeleteAccount + // Interface used by AccountDelete static TER deleteDelegate( ApplyView& view, diff --git a/include/xrpl/tx/transactors/dex/CancelOffer.h b/include/xrpl/tx/transactors/dex/OfferCancel.h similarity index 73% rename from include/xrpl/tx/transactors/dex/CancelOffer.h rename to include/xrpl/tx/transactors/dex/OfferCancel.h index 6107c3211f..c4c57ff3b4 100644 --- a/include/xrpl/tx/transactors/dex/CancelOffer.h +++ b/include/xrpl/tx/transactors/dex/OfferCancel.h @@ -5,12 +5,12 @@ namespace xrpl { -class CancelOffer : public Transactor +class OfferCancel : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit CancelOffer(ApplyContext& ctx) : Transactor(ctx) + explicit OfferCancel(ApplyContext& ctx) : Transactor(ctx) { } @@ -24,6 +24,4 @@ public: doApply() override; }; -using OfferCancel = CancelOffer; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/dex/CreateOffer.h b/include/xrpl/tx/transactors/dex/OfferCreate.h similarity index 93% rename from include/xrpl/tx/transactors/dex/CreateOffer.h rename to include/xrpl/tx/transactors/dex/OfferCreate.h index cb15d08ace..2179180054 100644 --- a/include/xrpl/tx/transactors/dex/CreateOffer.h +++ b/include/xrpl/tx/transactors/dex/OfferCreate.h @@ -9,13 +9,13 @@ class PaymentSandbox; class Sandbox; /** Transactor specialized for creating offers in the ledger. */ -class CreateOffer : public Transactor +class OfferCreate : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; /** Construct a Transactor subclass that creates an offer in the ledger. */ - explicit CreateOffer(ApplyContext& ctx) : Transactor(ctx) + explicit OfferCreate(ApplyContext& ctx) : Transactor(ctx) { } @@ -74,6 +74,4 @@ private: std::function)> const& setDir); }; -using OfferCreate = CreateOffer; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/oracle/DeleteOracle.h b/include/xrpl/tx/transactors/oracle/OracleDelete.h similarity index 79% rename from include/xrpl/tx/transactors/oracle/DeleteOracle.h rename to include/xrpl/tx/transactors/oracle/OracleDelete.h index bff33205aa..9d1e6d3a44 100644 --- a/include/xrpl/tx/transactors/oracle/DeleteOracle.h +++ b/include/xrpl/tx/transactors/oracle/OracleDelete.h @@ -10,15 +10,15 @@ namespace xrpl { to decentralized applications (dApps) on the blockchain. This implementation conforms to the requirements specified in the XLS-47d. - The DeleteOracle transactor implements the deletion of Oracle objects. + The OracleDelete transactor implements the deletion of Oracle objects. */ -class DeleteOracle : public Transactor +class OracleDelete : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit DeleteOracle(ApplyContext& ctx) : Transactor(ctx) + explicit OracleDelete(ApplyContext& ctx) : Transactor(ctx) { } @@ -39,6 +39,4 @@ public: beast::Journal j); }; -using OracleDelete = DeleteOracle; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/oracle/SetOracle.h b/include/xrpl/tx/transactors/oracle/OracleSet.h similarity index 77% rename from include/xrpl/tx/transactors/oracle/SetOracle.h rename to include/xrpl/tx/transactors/oracle/OracleSet.h index be1a7b8821..d879d14a84 100644 --- a/include/xrpl/tx/transactors/oracle/SetOracle.h +++ b/include/xrpl/tx/transactors/oracle/OracleSet.h @@ -10,15 +10,15 @@ namespace xrpl { to decentralized applications (dApps) on the blockchain. This implementation conforms to the requirements specified in the XLS-47d. - The SetOracle transactor implements creating or updating Oracle objects. + The OracleSet transactor implements creating or updating Oracle objects. */ -class SetOracle : public Transactor +class OracleSet : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit SetOracle(ApplyContext& ctx) : Transactor(ctx) + explicit OracleSet(ApplyContext& ctx) : Transactor(ctx) { } @@ -32,6 +32,4 @@ public: doApply() override; }; -using OracleSet = SetOracle; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/payment/DepositPreauth.h b/include/xrpl/tx/transactors/payment/DepositPreauth.h index 24050da600..b397a81748 100644 --- a/include/xrpl/tx/transactors/payment/DepositPreauth.h +++ b/include/xrpl/tx/transactors/payment/DepositPreauth.h @@ -25,7 +25,7 @@ public: TER doApply() override; - // Interface used by DeleteAccount + // Interface used by AccountDelete static TER removeFromLedger(ApplyView& view, uint256 const& delIndex, beast::Journal j); }; diff --git a/include/xrpl/tx/transactors/payment_channel/PayChanClaim.h b/include/xrpl/tx/transactors/payment_channel/PaymentChannelClaim.h similarity index 76% rename from include/xrpl/tx/transactors/payment_channel/PayChanClaim.h rename to include/xrpl/tx/transactors/payment_channel/PaymentChannelClaim.h index a2728a60e7..449e503bc4 100644 --- a/include/xrpl/tx/transactors/payment_channel/PayChanClaim.h +++ b/include/xrpl/tx/transactors/payment_channel/PaymentChannelClaim.h @@ -4,12 +4,12 @@ namespace xrpl { -class PayChanClaim : public Transactor +class PaymentChannelClaim : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit PayChanClaim(ApplyContext& ctx) : Transactor(ctx) + explicit PaymentChannelClaim(ApplyContext& ctx) : Transactor(ctx) { } @@ -29,6 +29,4 @@ public: doApply() override; }; -using PaymentChannelClaim = PayChanClaim; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/payment_channel/PayChanCreate.h b/include/xrpl/tx/transactors/payment_channel/PaymentChannelCreate.h similarity index 73% rename from include/xrpl/tx/transactors/payment_channel/PayChanCreate.h rename to include/xrpl/tx/transactors/payment_channel/PaymentChannelCreate.h index ff59fdbdd0..7fdacf9b3a 100644 --- a/include/xrpl/tx/transactors/payment_channel/PayChanCreate.h +++ b/include/xrpl/tx/transactors/payment_channel/PaymentChannelCreate.h @@ -4,12 +4,12 @@ namespace xrpl { -class PayChanCreate : public Transactor +class PaymentChannelCreate : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; - explicit PayChanCreate(ApplyContext& ctx) : Transactor(ctx) + explicit PaymentChannelCreate(ApplyContext& ctx) : Transactor(ctx) { } @@ -26,6 +26,4 @@ public: doApply() override; }; -using PaymentChannelCreate = PayChanCreate; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/payment_channel/PayChanFund.h b/include/xrpl/tx/transactors/payment_channel/PaymentChannelFund.h similarity index 72% rename from include/xrpl/tx/transactors/payment_channel/PayChanFund.h rename to include/xrpl/tx/transactors/payment_channel/PaymentChannelFund.h index ac0f9e0ce2..69f74a4c53 100644 --- a/include/xrpl/tx/transactors/payment_channel/PayChanFund.h +++ b/include/xrpl/tx/transactors/payment_channel/PaymentChannelFund.h @@ -4,12 +4,12 @@ namespace xrpl { -class PayChanFund : public Transactor +class PaymentChannelFund : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; - explicit PayChanFund(ApplyContext& ctx) : Transactor(ctx) + explicit PaymentChannelFund(ApplyContext& ctx) : Transactor(ctx) { } @@ -23,6 +23,4 @@ public: doApply() override; }; -using PaymentChannelFund = PayChanFund; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/system/CreateTicket.h b/include/xrpl/tx/transactors/system/TicketCreate.h similarity index 91% rename from include/xrpl/tx/transactors/system/CreateTicket.h rename to include/xrpl/tx/transactors/system/TicketCreate.h index 867ad99c12..88d83c37a7 100644 --- a/include/xrpl/tx/transactors/system/CreateTicket.h +++ b/include/xrpl/tx/transactors/system/TicketCreate.h @@ -4,7 +4,7 @@ namespace xrpl { -class CreateTicket : public Transactor +class TicketCreate : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; @@ -25,7 +25,7 @@ public: // average, 1.25 ms. // // Using that same test set up creating 250 Tickets in a single - // CreateTicket::doApply() in a unit test took, on average, 1.21 ms. + // TicketCreate::doApply() in a unit test took, on average, 1.21 ms. // // So, for the moment, a single transaction creating 250 Tickets takes // about the same compute time as a single compute-intensive payment. @@ -41,7 +41,7 @@ public: // ledger-stuffing with Tickets. constexpr static std::uint32_t maxTicketThreshold = 250; - explicit CreateTicket(ApplyContext& ctx) : Transactor(ctx) + explicit TicketCreate(ApplyContext& ctx) : Transactor(ctx) { } @@ -61,6 +61,4 @@ public: doApply() override; }; -using TicketCreate = CreateTicket; - } // namespace xrpl diff --git a/include/xrpl/tx/transactors/token/SetTrust.h b/include/xrpl/tx/transactors/token/TrustSet.h similarity index 81% rename from include/xrpl/tx/transactors/token/SetTrust.h rename to include/xrpl/tx/transactors/token/TrustSet.h index 47ec26b6ad..2e67aaeded 100644 --- a/include/xrpl/tx/transactors/token/SetTrust.h +++ b/include/xrpl/tx/transactors/token/TrustSet.h @@ -5,12 +5,12 @@ namespace xrpl { -class SetTrust : public Transactor +class TrustSet : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; - explicit SetTrust(ApplyContext& ctx) : Transactor(ctx) + explicit TrustSet(ApplyContext& ctx) : Transactor(ctx) { } @@ -30,6 +30,4 @@ public: doApply() override; }; -using TrustSet = SetTrust; - } // namespace xrpl diff --git a/sanitizers/suppressions/ubsan.supp b/sanitizers/suppressions/ubsan.supp index bd38e43c32..a02cbb17de 100644 --- a/sanitizers/suppressions/ubsan.supp +++ b/sanitizers/suppressions/ubsan.supp @@ -104,7 +104,7 @@ undefined:src/xrpld/app/misc/NetworkOPs.cpp undefined:src/libxrpl/json/json_value.cpp undefined:src/xrpld/app/paths/detail/StrandFlow.h undefined:src/xrpld/app/tx/detail/NFTokenMint.cpp -undefined:src/xrpld/app/tx/detail/SetOracle.cpp +undefined:src/xrpld/app/tx/detail/OracleSet.cpp undefined:src/xrpld/core/detail/JobQueue.cpp undefined:src/xrpld/core/detail/Workers.cpp undefined:src/xrpld/rpc/detail/Role.cpp @@ -154,7 +154,7 @@ unsigned-integer-overflow:src/xrpld/app/misc/detail/AmendmentTable.cpp unsigned-integer-overflow:src/xrpld/app/misc/NetworkOPs.cpp unsigned-integer-overflow:src/xrpld/app/paths/detail/StrandFlow.h unsigned-integer-overflow:src/xrpld/app/tx/detail/NFTokenMint.cpp -unsigned-integer-overflow:src/xrpld/app/tx/detail/SetOracle.cpp +unsigned-integer-overflow:src/xrpld/app/tx/detail/OracleSet.cpp unsigned-integer-overflow:src/xrpld/rpc/detail/Role.cpp unsigned-integer-overflow:src/xrpld/rpc/handlers/GetAggregatePrice.cpp unsigned-integer-overflow:xrpl/basics/base_uint.h @@ -188,8 +188,8 @@ undefined:src/test/app/Loan_test.cpp # Source tree restructured paths (libxrpl/tx/transactors/) # These duplicate the xrpld/app/tx/detail entries above for the new layout -unsigned-integer-overflow:src/libxrpl/tx/transactors/oracle/SetOracle.cpp -undefined:src/libxrpl/tx/transactors/oracle/SetOracle.cpp +unsigned-integer-overflow:src/libxrpl/tx/transactors/oracle/OracleSet.cpp +undefined:src/libxrpl/tx/transactors/oracle/OracleSet.cpp unsigned-integer-overflow:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp undefined:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index e76f0bfddc..d5c94a9981 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -3234,7 +3234,7 @@ cleanupOnAccountDelete( { // Directory node has an invalid index. Bail out. // LCOV_EXCL_START - JLOG(j.fatal()) << "DeleteAccount: Directory node in ledger " << view.seq() + JLOG(j.fatal()) << "AccountDelete: Directory node in ledger " << view.seq() << " has index to object that is missing: " << to_string(dirEntry); return tefBAD_LEDGER; // LCOV_EXCL_STOP @@ -3269,7 +3269,7 @@ cleanupOnAccountDelete( if (uDirEntry == 0) { // LCOV_EXCL_START - JLOG(j.error()) << "DeleteAccount iterator re-validation failed."; + JLOG(j.error()) << "AccountDelete iterator re-validation failed."; return tefBAD_LEDGER; // LCOV_EXCL_STOP } diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index aabe8395ae..61a64b2a54 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -219,7 +219,7 @@ book_t::operator()(Book const& b) const Keylet line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept { - // There is code in SetTrust that calls us with id0 == id1, to allow users + // There is code in TrustSet that calls us with id0 == id1, to allow users // to locate and delete such "weird" trustlines. If we remove that code, we // could enable this assert: // XRPL_ASSERT(id0 != id1, "xrpl::keylet::line : accounts must be diff --git a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp b/src/libxrpl/tx/transactors/account/AccountDelete.cpp similarity index 91% rename from src/libxrpl/tx/transactors/account/DeleteAccount.cpp rename to src/libxrpl/tx/transactors/account/AccountDelete.cpp index a70cc24549..b50b254ec9 100644 --- a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp +++ b/src/libxrpl/tx/transactors/account/AccountDelete.cpp @@ -7,18 +7,18 @@ #include #include #include -#include -#include +#include +#include #include #include #include -#include +#include #include namespace xrpl { bool -DeleteAccount::checkExtraFeatures(PreflightContext const& ctx) +AccountDelete::checkExtraFeatures(PreflightContext const& ctx) { if (ctx.tx.isFieldPresent(sfCredentialIDs) && !ctx.rules.enabled(featureCredentials)) return false; @@ -27,7 +27,7 @@ DeleteAccount::checkExtraFeatures(PreflightContext const& ctx) } NotTEC -DeleteAccount::preflight(PreflightContext const& ctx) +AccountDelete::preflight(PreflightContext const& ctx) { if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) { @@ -42,7 +42,7 @@ DeleteAccount::preflight(PreflightContext const& ctx) } XRPAmount -DeleteAccount::calculateBaseFee(ReadView const& view, STTx const& tx) +AccountDelete::calculateBaseFee(ReadView const& view, STTx const& tx) { // The fee required for AccountDelete is one owner reserve. return calculateOwnerReserveFee(view, tx); @@ -80,7 +80,7 @@ removeSignersFromLedger( std::shared_ptr const& sleDel, beast::Journal j) { - return SetSignerList::removeFromLedger(registry, view, account, j); + return SignerListSet::removeFromLedger(registry, view, account, j); } TER @@ -143,7 +143,7 @@ removeOracleFromLedger( std::shared_ptr const& sleDel, beast::Journal j) { - return DeleteOracle::deleteOracle(view, sleDel, account, j); + return OracleDelete::deleteOracle(view, sleDel, account, j); } TER @@ -204,7 +204,7 @@ nonObligationDeleter(LedgerEntryType t) } // namespace TER -DeleteAccount::preclaim(PreclaimContext const& ctx) +AccountDelete::preclaim(PreclaimContext const& ctx) { AccountID const account{ctx.tx[sfAccount]}; AccountID const dst{ctx.tx[sfDestination]}; @@ -234,7 +234,7 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) } auto sleAccount = ctx.view.read(keylet::account(account)); - XRPL_ASSERT(sleAccount, "xrpl::DeleteAccount::preclaim : non-null account"); + XRPL_ASSERT(sleAccount, "xrpl::AccountDelete::preclaim : non-null account"); if (!sleAccount) return terNO_ACCOUNT; @@ -303,7 +303,7 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) { // Directory node has an invalid index. Bail out. // LCOV_EXCL_START - JLOG(ctx.j.fatal()) << "DeleteAccount: directory node in ledger " << ctx.view.seq() + JLOG(ctx.j.fatal()) << "AccountDelete: directory node in ledger " << ctx.view.seq() << " has index to object that is missing: " << to_string(dirEntry); return tefBAD_LEDGER; // LCOV_EXCL_STOP @@ -325,14 +325,14 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) } TER -DeleteAccount::doApply() +AccountDelete::doApply() { auto src = view().peek(keylet::account(account_)); - XRPL_ASSERT(src, "xrpl::DeleteAccount::doApply : non-null source account"); + XRPL_ASSERT(src, "xrpl::AccountDelete::doApply : non-null source account"); auto const dstID = ctx_.tx[sfDestination]; auto dst = view().peek(keylet::account(dstID)); - XRPL_ASSERT(dst, "xrpl::DeleteAccount::doApply : non-null destination account"); + XRPL_ASSERT(dst, "xrpl::AccountDelete::doApply : non-null destination account"); if (!src || !dst) return tefBAD_LEDGER; // LCOV_EXCL_LINE @@ -361,9 +361,9 @@ DeleteAccount::doApply() // LCOV_EXCL_START UNREACHABLE( - "xrpl::DeleteAccount::doApply : undeletable item not found " + "xrpl::AccountDelete::doApply : undeletable item not found " "in preclaim"); - JLOG(j_.error()) << "DeleteAccount undeletable item not " + JLOG(j_.error()) << "AccountDelete undeletable item not " "found in preclaim."; return {tecHAS_OBLIGATIONS, SkipEntry::No}; // LCOV_EXCL_STOP @@ -379,13 +379,13 @@ DeleteAccount::doApply() ctx_.deliver(remainingBalance); XRPL_ASSERT( - (*src)[sfBalance] == XRPAmount(0), "xrpl::DeleteAccount::doApply : source balance is zero"); + (*src)[sfBalance] == XRPAmount(0), "xrpl::AccountDelete::doApply : source balance is zero"); // If there's still an owner directory associated with the source account // delete it. if (view().exists(ownerDirKeylet) && !view().emptyDirDelete(ownerDirKeylet)) { - JLOG(j_.error()) << "DeleteAccount cannot delete root dir node of " << toBase58(account_); + JLOG(j_.error()) << "AccountDelete cannot delete root dir node of " << toBase58(account_); return tecHAS_OBLIGATIONS; } diff --git a/src/libxrpl/tx/transactors/account/SetAccount.cpp b/src/libxrpl/tx/transactors/account/AccountSet.cpp similarity index 97% rename from src/libxrpl/tx/transactors/account/SetAccount.cpp rename to src/libxrpl/tx/transactors/account/AccountSet.cpp index 9bb92c2ea5..a3afe2092c 100644 --- a/src/libxrpl/tx/transactors/account/SetAccount.cpp +++ b/src/libxrpl/tx/transactors/account/AccountSet.cpp @@ -5,15 +5,15 @@ #include #include #include -#include +#include #include namespace xrpl { TxConsequences -SetAccount::makeTxConsequences(PreflightContext const& ctx) +AccountSet::makeTxConsequences(PreflightContext const& ctx) { - // The SetAccount may be a blocker, but only if it sets or clears + // The AccountSet may be a blocker, but only if it sets or clears // specific account flags. auto getTxConsequencesCategory = [](STTx const& tx) { if (std::uint32_t const uTxFlags = tx.getFlags(); @@ -37,13 +37,13 @@ SetAccount::makeTxConsequences(PreflightContext const& ctx) } std::uint32_t -SetAccount::getFlagsMask(PreflightContext const& ctx) +AccountSet::getFlagsMask(PreflightContext const& ctx) { return tfAccountSetMask; } NotTEC -SetAccount::preflight(PreflightContext const& ctx) +AccountSet::preflight(PreflightContext const& ctx) { auto& tx = ctx.tx; auto& j = ctx.j; @@ -150,9 +150,9 @@ SetAccount::preflight(PreflightContext const& ctx) } NotTEC -SetAccount::checkPermission(ReadView const& view, STTx const& tx) +AccountSet::checkPermission(ReadView const& view, STTx const& tx) { - // SetAccount is prohibited to be granted on a transaction level, + // AccountSet is prohibited to be granted on a transaction level, // but some granular permissions are allowed. auto const delegate = tx[~sfDelegate]; if (!delegate) @@ -199,7 +199,7 @@ SetAccount::checkPermission(ReadView const& view, STTx const& tx) } TER -SetAccount::preclaim(PreclaimContext const& ctx) +AccountSet::preclaim(PreclaimContext const& ctx) { auto const id = ctx.tx[sfAccount]; @@ -262,7 +262,7 @@ SetAccount::preclaim(PreclaimContext const& ctx) } TER -SetAccount::doApply() +AccountSet::doApply() { auto const sle = view().peek(keylet::account(account_)); if (!sle) diff --git a/src/libxrpl/tx/transactors/account/SetSignerList.cpp b/src/libxrpl/tx/transactors/account/SignerListSet.cpp similarity index 93% rename from src/libxrpl/tx/transactors/account/SetSignerList.cpp rename to src/libxrpl/tx/transactors/account/SignerListSet.cpp index 54fe91aaa6..399e832740 100644 --- a/src/libxrpl/tx/transactors/account/SetSignerList.cpp +++ b/src/libxrpl/tx/transactors/account/SignerListSet.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -19,8 +19,8 @@ namespace xrpl { // setting the sfSignerListID to zero in all cases. static std::uint32_t const DEFAULT_SIGNER_LIST_ID = 0; -std::tuple, SetSignerList::Operation> -SetSignerList::determineOperation(STTx const& tx, ApplyFlags flags, beast::Journal j) +std::tuple, SignerListSet::Operation> +SignerListSet::determineOperation(STTx const& tx, ApplyFlags flags, beast::Journal j) { // Check the quorum. A non-zero quorum means we're creating or replacing // the list. A zero quorum means we're destroying the list. @@ -51,14 +51,14 @@ SetSignerList::determineOperation(STTx const& tx, ApplyFlags flags, beast::Journ } std::uint32_t -SetSignerList::getFlagsMask(PreflightContext const& ctx) +SignerListSet::getFlagsMask(PreflightContext const& ctx) { // 0 means "Allow any flags" return ctx.rules.enabled(fixInvalidTxFlags) ? tfUniversalMask : 0; } NotTEC -SetSignerList::preflight(PreflightContext const& ctx) +SignerListSet::preflight(PreflightContext const& ctx) { auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j); @@ -88,7 +88,7 @@ SetSignerList::preflight(PreflightContext const& ctx) } TER -SetSignerList::doApply() +SignerListSet::doApply() { // Perform the operation preCompute() decided on. switch (do_) @@ -103,22 +103,22 @@ SetSignerList::doApply() break; } // LCOV_EXCL_START - UNREACHABLE("xrpl::SetSignerList::doApply : invalid operation"); + UNREACHABLE("xrpl::SignerListSet::doApply : invalid operation"); return temMALFORMED; // LCOV_EXCL_STOP } void -SetSignerList::preCompute() +SignerListSet::preCompute() { // Get the quorum and operation info. auto result = determineOperation(ctx_.tx, view().flags(), j_); XRPL_ASSERT( isTesSuccess(std::get<0>(result)), - "xrpl::SetSignerList::preCompute : result is tesSUCCESS"); + "xrpl::SignerListSet::preCompute : result is tesSUCCESS"); XRPL_ASSERT( std::get<3>(result) != unknown, - "xrpl::SetSignerList::preCompute : result is known operation"); + "xrpl::SignerListSet::preCompute : result is known operation"); quorum_ = std::get<1>(result); signers_ = std::get<2>(result); @@ -204,7 +204,7 @@ removeSignersFromLedger( } TER -SetSignerList::removeFromLedger( +SignerListSet::removeFromLedger( ServiceRegistry& registry, ApplyView& view, AccountID const& account, @@ -219,7 +219,7 @@ SetSignerList::removeFromLedger( } NotTEC -SetSignerList::validateQuorumAndSignerEntries( +SignerListSet::validateQuorumAndSignerEntries( std::uint32_t quorum, std::vector const& signers, AccountID const& account, @@ -239,7 +239,7 @@ SetSignerList::validateQuorumAndSignerEntries( // Make sure there are no duplicate signers. XRPL_ASSERT( std::is_sorted(signers.begin(), signers.end()), - "xrpl::SetSignerList::validateQuorumAndSignerEntries : sorted " + "xrpl::SignerListSet::validateQuorumAndSignerEntries : sorted " "signers"); if (std::adjacent_find(signers.begin(), signers.end()) != signers.end()) { @@ -278,7 +278,7 @@ SetSignerList::validateQuorumAndSignerEntries( } TER -SetSignerList::replaceSignerList() +SignerListSet::replaceSignerList() { auto const accountKeylet = keylet::account(account_); auto const ownerDirKeylet = keylet::ownerDir(account_); @@ -305,7 +305,7 @@ SetSignerList::replaceSignerList() // We check the reserve against the starting balance because we want to // allow dipping into the reserve to pay fees. This behavior is consistent - // with CreateTicket. + // with TicketCreate. if (preFeeBalance_ < newReserve) return tecINSUFFICIENT_RESERVE; @@ -334,7 +334,7 @@ SetSignerList::replaceSignerList() } TER -SetSignerList::destroySignerList() +SignerListSet::destroySignerList() { auto const accountKeylet = keylet::account(account_); // Destroying the signer list is only allowed if either the master key @@ -353,7 +353,7 @@ SetSignerList::destroySignerList() } void -SetSignerList::writeSignersToSLE(SLE::pointer const& ledgerEntry, std::uint32_t flags) const +SignerListSet::writeSignersToSLE(SLE::pointer const& ledgerEntry, std::uint32_t flags) const { // Assign the quorum, default SignerListID, and flags. if (ctx_.view().rules().enabled(fixIncludeKeyletFields)) diff --git a/src/libxrpl/tx/transactors/check/CancelCheck.cpp b/src/libxrpl/tx/transactors/check/CheckCancel.cpp similarity index 94% rename from src/libxrpl/tx/transactors/check/CancelCheck.cpp rename to src/libxrpl/tx/transactors/check/CheckCancel.cpp index 59d80fb27e..d2a77698e0 100644 --- a/src/libxrpl/tx/transactors/check/CancelCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCancel.cpp @@ -5,18 +5,18 @@ #include #include #include -#include +#include namespace xrpl { NotTEC -CancelCheck::preflight(PreflightContext const& ctx) +CheckCancel::preflight(PreflightContext const& ctx) { return tesSUCCESS; } TER -CancelCheck::preclaim(PreclaimContext const& ctx) +CheckCancel::preclaim(PreclaimContext const& ctx) { auto const sleCheck = ctx.view.read(keylet::check(ctx.tx[sfCheckID])); if (!sleCheck) @@ -45,7 +45,7 @@ CancelCheck::preclaim(PreclaimContext const& ctx) } TER -CancelCheck::doApply() +CheckCancel::doApply() { auto const sleCheck = view().peek(keylet::check(ctx_.tx[sfCheckID])); if (!sleCheck) diff --git a/src/libxrpl/tx/transactors/check/CashCheck.cpp b/src/libxrpl/tx/transactors/check/CheckCash.cpp similarity index 99% rename from src/libxrpl/tx/transactors/check/CashCheck.cpp rename to src/libxrpl/tx/transactors/check/CheckCash.cpp index cba945cc82..2edd3c3a9c 100644 --- a/src/libxrpl/tx/transactors/check/CashCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCash.cpp @@ -6,14 +6,14 @@ #include #include #include -#include +#include #include namespace xrpl { NotTEC -CashCheck::preflight(PreflightContext const& ctx) +CheckCash::preflight(PreflightContext const& ctx) { // Exactly one of Amount or DeliverMin must be present. auto const optAmount = ctx.tx[~sfAmount]; @@ -44,7 +44,7 @@ CashCheck::preflight(PreflightContext const& ctx) } TER -CashCheck::preclaim(PreclaimContext const& ctx) +CheckCash::preclaim(PreclaimContext const& ctx) { auto const sleCheck = ctx.view.read(keylet::check(ctx.tx[sfCheckID])); if (!sleCheck) @@ -196,7 +196,7 @@ CashCheck::preclaim(PreclaimContext const& ctx) } TER -CashCheck::doApply() +CheckCash::doApply() { // Flow requires that we operate on a PaymentSandbox, rather than // directly on a View. diff --git a/src/libxrpl/tx/transactors/check/CreateCheck.cpp b/src/libxrpl/tx/transactors/check/CheckCreate.cpp similarity index 97% rename from src/libxrpl/tx/transactors/check/CreateCheck.cpp rename to src/libxrpl/tx/transactors/check/CheckCreate.cpp index 1530b20f40..43e000ad5b 100644 --- a/src/libxrpl/tx/transactors/check/CreateCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCreate.cpp @@ -4,12 +4,12 @@ #include #include #include -#include +#include namespace xrpl { NotTEC -CreateCheck::preflight(PreflightContext const& ctx) +CheckCreate::preflight(PreflightContext const& ctx) { if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) { @@ -47,7 +47,7 @@ CreateCheck::preflight(PreflightContext const& ctx) } TER -CreateCheck::preclaim(PreclaimContext const& ctx) +CheckCreate::preclaim(PreclaimContext const& ctx) { AccountID const dstId{ctx.tx[sfDestination]}; auto const sleDst = ctx.view.read(keylet::account(dstId)); @@ -128,7 +128,7 @@ CreateCheck::preclaim(PreclaimContext const& ctx) } TER -CreateCheck::doApply() +CheckCreate::doApply() { auto const sle = view().peek(keylet::account(account_)); if (!sle) diff --git a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp index f43367ac21..b822ff6b84 100644 --- a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp @@ -538,7 +538,7 @@ AMMWithdraw::withdraw( auto const balance = (*sleAccount)[sfBalance].xrp(); std::uint32_t const ownerCount = sleAccount->at(sfOwnerCount); - // See also SetTrust::doApply() + // See also TrustSet::doApply() XRPAmount const reserve( (ownerCount < 2) ? XRPAmount(beast::zero) : view.fees().accountReserve(ownerCount + 1)); diff --git a/src/libxrpl/tx/transactors/dex/CancelOffer.cpp b/src/libxrpl/tx/transactors/dex/OfferCancel.cpp similarity index 85% rename from src/libxrpl/tx/transactors/dex/CancelOffer.cpp rename to src/libxrpl/tx/transactors/dex/OfferCancel.cpp index 2549fd327e..58f9525f61 100644 --- a/src/libxrpl/tx/transactors/dex/CancelOffer.cpp +++ b/src/libxrpl/tx/transactors/dex/OfferCancel.cpp @@ -1,16 +1,16 @@ #include #include #include -#include +#include namespace xrpl { NotTEC -CancelOffer::preflight(PreflightContext const& ctx) +OfferCancel::preflight(PreflightContext const& ctx) { if (!ctx.tx[sfOfferSequence]) { - JLOG(ctx.j.trace()) << "CancelOffer::preflight: missing sequence"; + JLOG(ctx.j.trace()) << "OfferCancel::preflight: missing sequence"; return temBAD_SEQUENCE; } @@ -20,7 +20,7 @@ CancelOffer::preflight(PreflightContext const& ctx) //------------------------------------------------------------------------------ TER -CancelOffer::preclaim(PreclaimContext const& ctx) +OfferCancel::preclaim(PreclaimContext const& ctx) { auto const id = ctx.tx[sfAccount]; auto const offerSequence = ctx.tx[sfOfferSequence]; @@ -42,7 +42,7 @@ CancelOffer::preclaim(PreclaimContext const& ctx) //------------------------------------------------------------------------------ TER -CancelOffer::doApply() +OfferCancel::doApply() { auto const offerSequence = ctx_.tx[sfOfferSequence]; diff --git a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp similarity index 97% rename from src/libxrpl/tx/transactors/dex/CreateOffer.cpp rename to src/libxrpl/tx/transactors/dex/OfferCreate.cpp index 58241803a9..90c00c6280 100644 --- a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp +++ b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp @@ -8,12 +8,12 @@ #include #include #include -#include +#include #include namespace xrpl { TxConsequences -CreateOffer::makeTxConsequences(PreflightContext const& ctx) +OfferCreate::makeTxConsequences(PreflightContext const& ctx) { auto calculateMaxXRPSpend = [](STTx const& tx) -> XRPAmount { auto const& amount{tx[sfTakerGets]}; @@ -24,7 +24,7 @@ CreateOffer::makeTxConsequences(PreflightContext const& ctx) } bool -CreateOffer::checkExtraFeatures(PreflightContext const& ctx) +OfferCreate::checkExtraFeatures(PreflightContext const& ctx) { if (ctx.tx.isFieldPresent(sfDomainID) && !ctx.rules.enabled(featurePermissionedDEX)) return false; @@ -33,7 +33,7 @@ CreateOffer::checkExtraFeatures(PreflightContext const& ctx) } std::uint32_t -CreateOffer::getFlagsMask(PreflightContext const& ctx) +OfferCreate::getFlagsMask(PreflightContext const& ctx) { // The tfOfferCreateMask is built assuming that PermissionedDEX is // enabled @@ -45,7 +45,7 @@ CreateOffer::getFlagsMask(PreflightContext const& ctx) } NotTEC -CreateOffer::preflight(PreflightContext const& ctx) +OfferCreate::preflight(PreflightContext const& ctx) { auto& tx = ctx.tx; auto& j = ctx.j; @@ -123,7 +123,7 @@ CreateOffer::preflight(PreflightContext const& ctx) } TER -CreateOffer::preclaim(PreclaimContext const& ctx) +OfferCreate::preclaim(PreclaimContext const& ctx) { auto const id = ctx.tx[sfAccount]; @@ -194,7 +194,7 @@ CreateOffer::preclaim(PreclaimContext const& ctx) } TER -CreateOffer::checkAcceptAsset( +OfferCreate::checkAcceptAsset( ReadView const& view, ApplyFlags const flags, AccountID const id, @@ -202,7 +202,7 @@ CreateOffer::checkAcceptAsset( Issue const& issue) { // Only valid for custom currencies - XRPL_ASSERT(!isXRP(issue.currency), "xrpl::CreateOffer::checkAcceptAsset : input is not XRP"); + XRPL_ASSERT(!isXRP(issue.currency), "xrpl::OfferCreate::checkAcceptAsset : input is not XRP"); auto const issuerAccount = view.read(keylet::account(issue.account)); @@ -264,7 +264,7 @@ CreateOffer::checkAcceptAsset( } std::pair -CreateOffer::flowCross( +OfferCreate::flowCross( PaymentSandbox& psb, PaymentSandbox& psbCancel, Amounts const& takerAmount, @@ -433,7 +433,7 @@ CreateOffer::flowCross( afterCross.out -= result.actualAmountOut; XRPL_ASSERT( afterCross.out >= beast::zero, - "xrpl::CreateOffer::flowCross : minimum offer"); + "xrpl::OfferCreate::flowCross : minimum offer"); if (afterCross.out < beast::zero) afterCross.out.clear(); afterCross.in = mulRound(afterCross.out, rate, takerAmount.in.issue(), true); @@ -452,7 +452,7 @@ CreateOffer::flowCross( } std::string -CreateOffer::format_amount(STAmount const& amount) +OfferCreate::format_amount(STAmount const& amount) { std::string txt = amount.getText(); txt += "/"; @@ -461,7 +461,7 @@ CreateOffer::format_amount(STAmount const& amount) } TER -CreateOffer::applyHybrid( +OfferCreate::applyHybrid( Sandbox& sb, std::shared_ptr sleOffer, Keylet const& offerKey, @@ -507,7 +507,7 @@ CreateOffer::applyHybrid( } std::pair -CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) +OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel) { using beast::zero; @@ -638,7 +638,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) // or give a tec. XRPL_ASSERT( isTesSuccess(result) || isTecClaim(result), - "xrpl::CreateOffer::applyGuts : result is tesSUCCESS or " + "xrpl::OfferCreate::applyGuts : result is tesSUCCESS or " "tecCLAIM"); if (auto stream = j_.trace()) @@ -659,10 +659,10 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) XRPL_ASSERT( saTakerGets.issue() == place_offer.in.issue(), - "xrpl::CreateOffer::applyGuts : taker gets issue match"); + "xrpl::OfferCreate::applyGuts : taker gets issue match"); XRPL_ASSERT( saTakerPays.issue() == place_offer.out.issue(), - "xrpl::CreateOffer::applyGuts : taker pays issue match"); + "xrpl::OfferCreate::applyGuts : taker pays issue match"); if (takerAmount != place_offer) crossed = true; @@ -692,7 +692,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) XRPL_ASSERT( saTakerPays > zero && saTakerGets > zero, - "xrpl::CreateOffer::applyGuts : taker pays and gets positive"); + "xrpl::OfferCreate::applyGuts : taker pays and gets positive"); if (!isTesSuccess(result)) { @@ -852,7 +852,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) } TER -CreateOffer::doApply() +OfferCreate::doApply() { // This is the ledger view that we work against. Transactions are applied // as we go on processing transactions. diff --git a/src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp b/src/libxrpl/tx/transactors/oracle/OracleDelete.cpp similarity index 89% rename from src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp rename to src/libxrpl/tx/transactors/oracle/OracleDelete.cpp index 78bba900da..e55d96e246 100644 --- a/src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp +++ b/src/libxrpl/tx/transactors/oracle/OracleDelete.cpp @@ -2,18 +2,18 @@ #include #include #include -#include +#include namespace xrpl { NotTEC -DeleteOracle::preflight(PreflightContext const& ctx) +OracleDelete::preflight(PreflightContext const& ctx) { return tesSUCCESS; } TER -DeleteOracle::preclaim(PreclaimContext const& ctx) +OracleDelete::preclaim(PreclaimContext const& ctx) { if (!ctx.view.exists(keylet::account(ctx.tx.getAccountID(sfAccount)))) return terNO_ACCOUNT; // LCOV_EXCL_LINE @@ -38,7 +38,7 @@ DeleteOracle::preclaim(PreclaimContext const& ctx) } TER -DeleteOracle::deleteOracle( +OracleDelete::deleteOracle( ApplyView& view, std::shared_ptr const& sle, AccountID const& account, @@ -69,7 +69,7 @@ DeleteOracle::deleteOracle( } TER -DeleteOracle::doApply() +OracleDelete::doApply() { if (auto sle = ctx_.view().peek(keylet::oracle(account_, ctx_.tx[sfOracleDocumentID]))) return deleteOracle(ctx_.view(), sle, account_, j_); diff --git a/src/libxrpl/tx/transactors/oracle/SetOracle.cpp b/src/libxrpl/tx/transactors/oracle/OracleSet.cpp similarity index 98% rename from src/libxrpl/tx/transactors/oracle/SetOracle.cpp rename to src/libxrpl/tx/transactors/oracle/OracleSet.cpp index 62ca6c5ea0..f0fc114d7f 100644 --- a/src/libxrpl/tx/transactors/oracle/SetOracle.cpp +++ b/src/libxrpl/tx/transactors/oracle/OracleSet.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include namespace xrpl { @@ -17,7 +17,7 @@ tokenPairKey(STObject const& pair) } NotTEC -SetOracle::preflight(PreflightContext const& ctx) +OracleSet::preflight(PreflightContext const& ctx) { auto const& dataSeries = ctx.tx.getFieldArray(sfPriceDataSeries); if (dataSeries.empty()) @@ -38,7 +38,7 @@ SetOracle::preflight(PreflightContext const& ctx) } TER -SetOracle::preclaim(PreclaimContext const& ctx) +OracleSet::preclaim(PreclaimContext const& ctx) { auto const sleSetter = ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount))); if (!sleSetter) @@ -178,7 +178,7 @@ setPriceDataInnerObjTemplate(STObject& obj) } TER -SetOracle::doApply() +OracleSet::doApply() { auto const oracleID = keylet::oracle(account_, ctx_.tx[sfOracleDocumentID]); diff --git a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp index ceb90411a4..2b9a8dfd3a 100644 --- a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp +++ b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp @@ -249,7 +249,7 @@ DepositPreauth::doApply() TER DepositPreauth::removeFromLedger(ApplyView& view, uint256 const& preauthIndex, beast::Journal j) { - // Existence already checked in preclaim and DeleteAccount + // Existence already checked in preclaim and AccountDelete auto const slePreauth{view.peek(keylet::depositPreauth(preauthIndex))}; if (!slePreauth) { diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp similarity index 90% rename from src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp rename to src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp index e70c1f11ac..a97b4c9e56 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp @@ -7,26 +7,26 @@ #include #include #include -#include +#include -#include +#include namespace xrpl { bool -PayChanClaim::checkExtraFeatures(PreflightContext const& ctx) +PaymentChannelClaim::checkExtraFeatures(PreflightContext const& ctx) { return !ctx.tx.isFieldPresent(sfCredentialIDs) || ctx.rules.enabled(featureCredentials); } std::uint32_t -PayChanClaim::getFlagsMask(PreflightContext const&) +PaymentChannelClaim::getFlagsMask(PreflightContext const&) { return tfPaymentChannelClaimMask; } NotTEC -PayChanClaim::preflight(PreflightContext const& ctx) +PaymentChannelClaim::preflight(PreflightContext const& ctx) { auto const bal = ctx.tx[~sfBalance]; if (bal && (!isXRP(*bal) || *bal <= beast::zero)) @@ -79,7 +79,7 @@ PayChanClaim::preflight(PreflightContext const& ctx) } TER -PayChanClaim::preclaim(PreclaimContext const& ctx) +PaymentChannelClaim::preclaim(PreclaimContext const& ctx) { if (!ctx.view.rules().enabled(featureCredentials)) return Transactor::preclaim(ctx); @@ -92,7 +92,7 @@ PayChanClaim::preclaim(PreclaimContext const& ctx) } TER -PayChanClaim::doApply() +PaymentChannelClaim::doApply() { Keylet const k(ltPAYCHAN, ctx_.tx[sfChannel]); auto const slep = ctx_.view().peek(k); @@ -151,7 +151,8 @@ PayChanClaim::doApply() (*slep)[sfBalance] = ctx_.tx[sfBalance]; XRPAmount const reqDelta = reqBalance - chanBalance; - XRPL_ASSERT(reqDelta >= beast::zero, "xrpl::PayChanClaim::doApply : minimum balance delta"); + XRPL_ASSERT( + reqDelta >= beast::zero, "xrpl::PaymentChannelClaim::doApply : minimum balance delta"); (*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta; ctx_.view().update(sled); ctx_.view().update(slep); diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp similarity index 95% rename from src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp rename to src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp index ccb0fa1a63..113dd89221 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanCreate.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include namespace xrpl { @@ -32,13 +32,13 @@ namespace xrpl { //------------------------------------------------------------------------------ TxConsequences -PayChanCreate::makeTxConsequences(PreflightContext const& ctx) +PaymentChannelCreate::makeTxConsequences(PreflightContext const& ctx) { return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()}; } NotTEC -PayChanCreate::preflight(PreflightContext const& ctx) +PaymentChannelCreate::preflight(PreflightContext const& ctx) { if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::zero)) return temBAD_AMOUNT; @@ -53,7 +53,7 @@ PayChanCreate::preflight(PreflightContext const& ctx) } TER -PayChanCreate::preclaim(PreclaimContext const& ctx) +PaymentChannelCreate::preclaim(PreclaimContext const& ctx) { auto const account = ctx.tx[sfAccount]; auto const sle = ctx.view.read(keylet::account(account)); @@ -103,7 +103,7 @@ PayChanCreate::preclaim(PreclaimContext const& ctx) } TER -PayChanCreate::doApply() +PaymentChannelCreate::doApply() { auto const account = ctx_.tx[sfAccount]; auto const sle = ctx_.view().peek(keylet::account(account)); diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp similarity index 89% rename from src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp rename to src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp index f01b8a7c40..6c08cc466c 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp @@ -1,20 +1,20 @@ #include #include #include -#include +#include -#include +#include namespace xrpl { TxConsequences -PayChanFund::makeTxConsequences(PreflightContext const& ctx) +PaymentChannelFund::makeTxConsequences(PreflightContext const& ctx) { return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()}; } NotTEC -PayChanFund::preflight(PreflightContext const& ctx) +PaymentChannelFund::preflight(PreflightContext const& ctx) { if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::zero)) return temBAD_AMOUNT; @@ -23,7 +23,7 @@ PayChanFund::preflight(PreflightContext const& ctx) } TER -PayChanFund::doApply() +PaymentChannelFund::doApply() { Keylet const k(ltPAYCHAN, ctx_.tx[sfChannel]); auto const slep = ctx_.view().peek(k); diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanHelpers.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp similarity index 95% rename from src/libxrpl/tx/transactors/payment_channel/PayChanHelpers.cpp rename to src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp index b761bb3fc3..75b68768ed 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanHelpers.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace xrpl { diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanHelpers.h b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.h similarity index 100% rename from src/libxrpl/tx/transactors/payment_channel/PayChanHelpers.h rename to src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.h diff --git a/src/libxrpl/tx/transactors/system/CreateTicket.cpp b/src/libxrpl/tx/transactors/system/TicketCreate.cpp similarity index 94% rename from src/libxrpl/tx/transactors/system/CreateTicket.cpp rename to src/libxrpl/tx/transactors/system/TicketCreate.cpp index b16cdeb7a2..8a9a5cbc93 100644 --- a/src/libxrpl/tx/transactors/system/CreateTicket.cpp +++ b/src/libxrpl/tx/transactors/system/TicketCreate.cpp @@ -3,19 +3,19 @@ #include #include #include -#include +#include namespace xrpl { TxConsequences -CreateTicket::makeTxConsequences(PreflightContext const& ctx) +TicketCreate::makeTxConsequences(PreflightContext const& ctx) { // Create TxConsequences identifying the number of sequences consumed. return TxConsequences{ctx.tx, ctx.tx[sfTicketCount]}; } NotTEC -CreateTicket::preflight(PreflightContext const& ctx) +TicketCreate::preflight(PreflightContext const& ctx) { if (std::uint32_t const count = ctx.tx[sfTicketCount]; count < minValidCount || count > maxValidCount) @@ -25,7 +25,7 @@ CreateTicket::preflight(PreflightContext const& ctx) } TER -CreateTicket::preclaim(PreclaimContext const& ctx) +TicketCreate::preclaim(PreclaimContext const& ctx) { auto const id = ctx.tx[sfAccount]; auto const sleAccountRoot = ctx.view.read(keylet::account(id)); @@ -51,7 +51,7 @@ CreateTicket::preclaim(PreclaimContext const& ctx) } TER -CreateTicket::doApply() +TicketCreate::doApply() { SLE::pointer const sleAccountRoot = view().peek(keylet::account(account_)); if (!sleAccountRoot) diff --git a/src/libxrpl/tx/transactors/token/SetTrust.cpp b/src/libxrpl/tx/transactors/token/TrustSet.cpp similarity index 98% rename from src/libxrpl/tx/transactors/token/SetTrust.cpp rename to src/libxrpl/tx/transactors/token/TrustSet.cpp index 7140d5ef2a..c620592619 100644 --- a/src/libxrpl/tx/transactors/token/SetTrust.cpp +++ b/src/libxrpl/tx/transactors/token/TrustSet.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace { @@ -46,13 +46,13 @@ computeFreezeFlags( namespace xrpl { std::uint32_t -SetTrust::getFlagsMask(PreflightContext const& ctx) +TrustSet::getFlagsMask(PreflightContext const& ctx) { return tfTrustSetMask; } NotTEC -SetTrust::preflight(PreflightContext const& ctx) +TrustSet::preflight(PreflightContext const& ctx) { auto& tx = ctx.tx; auto& j = ctx.j; @@ -106,7 +106,7 @@ SetTrust::preflight(PreflightContext const& ctx) } NotTEC -SetTrust::checkPermission(ReadView const& view, STTx const& tx) +TrustSet::checkPermission(ReadView const& view, STTx const& tx) { auto const delegate = tx[~sfDelegate]; if (!delegate) @@ -167,7 +167,7 @@ SetTrust::checkPermission(ReadView const& view, STTx const& tx) } TER -SetTrust::preclaim(PreclaimContext const& ctx) +TrustSet::preclaim(PreclaimContext const& ctx) { auto const id = ctx.tx[sfAccount]; @@ -226,7 +226,7 @@ SetTrust::preclaim(PreclaimContext const& ctx) if (sleDst && isPseudoAccount(sleDst)) { // If destination is AMM and the trustline doesn't exist then only allow - // SetTrust if the asset is AMM LP token and AMM is not in empty state. + // TrustSet if the asset is AMM LP token and AMM is not in empty state. if (sleDst->isFieldPresent(sfAMMID)) { if (ctx.view.exists(keylet::line(id, uDstAccountID, currency))) @@ -308,7 +308,7 @@ SetTrust::preclaim(PreclaimContext const& ctx) } TER -SetTrust::doApply() +TrustSet::doApply() { TER terResult = tesSUCCESS; diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 152a97fece..f84253588c 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -1973,7 +1973,7 @@ private: // Withdraw all tokens. testAMM([&](AMM& ammAlice, Env& env) { env(trust(carol, STAmount{ammAlice.lptIssue(), 10'000})); - // Can SetTrust only for AMM LP tokens + // Can TrustSet only for AMM LP tokens env(trust(carol, STAmount{Issue{EUR.currency, ammAlice.ammAccount()}, 10'000}), ter(tecNO_PERMISSION)); env.close(); @@ -4415,7 +4415,7 @@ private: AMM amm(env, C, TSTA(5'000), TSTB(5'000)); auto const ammIss = Issue(TSTA.currency, amm.ammAccount()); - // Can SetTrust only for AMM LP tokens + // Can TrustSet only for AMM LP tokens env(trust(D, STAmount{ammIss, 10'000}), ter(tecNO_PERMISSION)); env.close(); @@ -5108,7 +5108,7 @@ private: amm.withdrawAll(gw); BEAST_EXPECT(amm.ammExists()); - // Bid,Vote,Deposit,Withdraw,SetTrust failing with + // Bid,Vote,Deposit,Withdraw,TrustSet failing with // tecAMM_EMPTY. Deposit succeeds with tfTwoAssetIfEmpty option. env(amm.bid({ .account = alice, diff --git a/src/test/app/AccountSet_test.cpp b/src/test/app/AccountSet_test.cpp index 73e807a8aa..cfd7262a50 100644 --- a/src/test/app/AccountSet_test.cpp +++ b/src/test/app/AccountSet_test.cpp @@ -189,7 +189,7 @@ public: BEAST_EXPECT(!env.le(alice)->isFieldPresent(sfDomain)); // The upper limit on the length is 256 bytes - // (defined as DOMAIN_BYTES_MAX in SetAccount) + // (defined as DOMAIN_BYTES_MAX in AccountSet) // test the edge cases: 255, 256, 257. std::size_t const maxLength = 256; for (std::size_t len = maxLength - 1; len <= maxLength + 1; ++len) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index d9010d5d6e..ba61830758 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -2500,7 +2500,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite void testCreateOfferDestination(FeatureBitset features) { - // Explore the CreateOffer Destination field. + // Explore the OfferCreate Destination field. testcase("Create offer destination"); using namespace test::jtx; @@ -2915,7 +2915,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite void testCreateOfferExpiration(FeatureBitset features) { - // Explore the CreateOffer Expiration field. + // Explore the OfferCreate Expiration field. testcase("Create offer expiration"); using namespace test::jtx; diff --git a/src/test/app/Ticket_test.cpp b/src/test/app/Ticket_test.cpp index 35fc7ea979..7d300f61ca 100644 --- a/src/test/app/Ticket_test.cpp +++ b/src/test/app/Ticket_test.cpp @@ -9,7 +9,7 @@ namespace xrpl { class Ticket_test : public beast::unit_test::suite { - /// @brief Validate metadata for a successful CreateTicket transaction. + /// @brief Validate metadata for a successful TicketCreate transaction. /// /// @param env current jtx env (tx and meta are extracted using it) void diff --git a/src/test/app/SetTrust_test.cpp b/src/test/app/TrustSet_test.cpp similarity index 98% rename from src/test/app/SetTrust_test.cpp rename to src/test/app/TrustSet_test.cpp index fdc73eed79..51828fa544 100644 --- a/src/test/app/SetTrust_test.cpp +++ b/src/test/app/TrustSet_test.cpp @@ -7,7 +7,7 @@ namespace xrpl { namespace test { -class SetTrust_test : public beast::unit_test::suite +class TrustSet_test : public beast::unit_test::suite { public: void @@ -227,9 +227,9 @@ public: } void - testTicketSetTrust(FeatureBitset features) + testTicketTrustSet(FeatureBitset features) { - testcase("SetTrust using a ticket"); + testcase("TrustSet using a ticket"); using namespace jtx; @@ -274,7 +274,7 @@ public: void testMalformedTransaction(FeatureBitset features) { - testcase("SetTrust checks for malformed transactions"); + testcase("TrustSet checks for malformed transactions"); using namespace jtx; Env env{*this, features}; @@ -411,7 +411,7 @@ public: void testModifyQualityOfTrustline(FeatureBitset features, bool createQuality, bool createOnHighAcct) { - testcase << "SetTrust " << (createQuality ? "creates" : "removes") + testcase << "TrustSet " << (createQuality ? "creates" : "removes") << " quality of trustline for " << (createOnHighAcct ? "high" : "low") << " account"; @@ -576,7 +576,7 @@ public: // true, true case doesn't matter since creating a trustline ledger // entry requires reserve from the creator // independent of hi/low account ids for endpoints - testTicketSetTrust(features); + testTicketTrustSet(features); testMalformedTransaction(features); testModifyQualityOfTrustline(features, false, false); testModifyQualityOfTrustline(features, false, true); @@ -599,6 +599,6 @@ public: testWithFeats(sa); } }; -BEAST_DEFINE_TESTSUITE(SetTrust, app, xrpl); +BEAST_DEFINE_TESTSUITE(TrustSet, app, xrpl); } // namespace test } // namespace xrpl diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index 2b90cb8161..020fa501d5 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -938,7 +938,7 @@ TxQ::apply( // // o Additional transactions with Sequences should // follow preceding sequence-based transactions with no - // gaps (except for those required by CreateTicket + // gaps (except for those required by TicketCreate // transactions). // Find the entry in the queue that precedes the new From b1e5ba0518acb745f22d53c5d5dbdf1e8becca6c Mon Sep 17 00:00:00 2001 From: Jingchen Date: Wed, 18 Mar 2026 21:11:51 +0000 Subject: [PATCH 04/16] feat: Add code generator for transactions and ledger entries (#6443) Signed-off-by: JCW Co-authored-by: Bart --- .gersemi/definitions.cmake | 3 + .../scripts/levelization/results/ordering.txt | 5 + .../workflows/reusable-build-test-config.yml | 23 + .pre-commit-config.yaml | 9 +- cmake/XrplCore.cmake | 31 +- cmake/XrplProtocolAutogen.cmake | 287 ++++++ cspell.config.yaml | 2 + .../xrpl/protocol_autogen/LedgerEntryBase.h | 152 +++ .../protocol_autogen/LedgerEntryBuilderBase.h | 84 ++ include/xrpl/protocol_autogen/README.md | 79 ++ .../protocol_autogen/STObjectValidation.h | 43 + .../xrpl/protocol_autogen/TransactionBase.h | 457 +++++++++ .../protocol_autogen/TransactionBuilderBase.h | 269 +++++ include/xrpl/protocol_autogen/Utils.h | 14 + .../protocol_autogen/ledger_entries/AMM.h | 392 ++++++++ .../ledger_entries/AccountRoot.h | 834 ++++++++++++++++ .../ledger_entries/Amendments.h | 236 +++++ .../protocol_autogen/ledger_entries/Bridge.h | 346 +++++++ .../protocol_autogen/ledger_entries/Check.h | 427 ++++++++ .../ledger_entries/Credential.h | 344 +++++++ .../protocol_autogen/ledger_entries/DID.h | 296 ++++++ .../ledger_entries/Delegate.h | 240 +++++ .../ledger_entries/DepositPreauth.h | 262 +++++ .../ledger_entries/DirectoryNode.h | 563 +++++++++++ .../protocol_autogen/ledger_entries/Escrow.h | 554 +++++++++++ .../ledger_entries/FeeSettings.h | 410 ++++++++ .../ledger_entries/LedgerHashes.h | 189 ++++ .../protocol_autogen/ledger_entries/Loan.h | 930 ++++++++++++++++++ .../ledger_entries/LoanBroker.h | 591 +++++++++++ .../protocol_autogen/ledger_entries/MPToken.h | 285 ++++++ .../ledger_entries/MPTokenIssuance.h | 484 +++++++++ .../ledger_entries/NFTokenOffer.h | 333 +++++++ .../ledger_entries/NFTokenPage.h | 238 +++++ .../ledger_entries/NegativeUNL.h | 271 +++++ .../protocol_autogen/ledger_entries/Offer.h | 417 ++++++++ .../protocol_autogen/ledger_entries/Oracle.h | 358 +++++++ .../ledger_entries/PayChannel.h | 521 ++++++++++ .../ledger_entries/PermissionedDomain.h | 240 +++++ .../ledger_entries/RippleState.h | 425 ++++++++ .../ledger_entries/SignerList.h | 275 ++++++ .../protocol_autogen/ledger_entries/Ticket.h | 215 ++++ .../protocol_autogen/ledger_entries/Vault.h | 521 ++++++++++ .../ledger_entries/XChainOwnedClaimID.h | 312 ++++++ .../XChainOwnedCreateAccountClaimID.h | 264 +++++ .../protocol_autogen/transactions/AMMBid.h | 262 +++++ .../transactions/AMMClawback.h | 214 ++++ .../protocol_autogen/transactions/AMMCreate.h | 177 ++++ .../protocol_autogen/transactions/AMMDelete.h | 153 +++ .../transactions/AMMDeposit.h | 338 +++++++ .../protocol_autogen/transactions/AMMVote.h | 177 ++++ .../transactions/AMMWithdraw.h | 301 ++++++ .../transactions/AccountDelete.h | 203 ++++ .../transactions/AccountSet.h | 475 +++++++++ .../protocol_autogen/transactions/Batch.h | 164 +++ .../transactions/CheckCancel.h | 129 +++ .../protocol_autogen/transactions/CheckCash.h | 203 ++++ .../transactions/CheckCreate.h | 264 +++++ .../protocol_autogen/transactions/Clawback.h | 168 ++++ .../transactions/CredentialAccept.h | 153 +++ .../transactions/CredentialCreate.h | 227 +++++ .../transactions/CredentialDelete.h | 203 ++++ .../protocol_autogen/transactions/DIDDelete.h | 105 ++ .../protocol_autogen/transactions/DIDSet.h | 216 ++++ .../transactions/DelegateSet.h | 153 +++ .../transactions/DepositPreauth.h | 249 +++++ .../transactions/EnableAmendment.h | 153 +++ .../transactions/EscrowCancel.h | 153 +++ .../transactions/EscrowCreate.h | 303 ++++++ .../transactions/EscrowFinish.h | 264 +++++ .../transactions/LedgerStateFix.h | 166 ++++ .../transactions/LoanBrokerCoverClawback.h | 181 ++++ .../transactions/LoanBrokerCoverDeposit.h | 155 +++ .../transactions/LoanBrokerCoverWithdraw.h | 229 +++++ .../transactions/LoanBrokerDelete.h | 129 +++ .../transactions/LoanBrokerSet.h | 351 +++++++ .../transactions/LoanDelete.h | 129 +++ .../transactions/LoanManage.h | 129 +++ .../protocol_autogen/transactions/LoanPay.h | 155 +++ .../protocol_autogen/transactions/LoanSet.h | 706 +++++++++++++ .../transactions/MPTokenAuthorize.h | 166 ++++ .../transactions/MPTokenIssuanceCreate.h | 327 ++++++ .../transactions/MPTokenIssuanceDestroy.h | 129 +++ .../transactions/MPTokenIssuanceSet.h | 314 ++++++ .../transactions/NFTokenAcceptOffer.h | 216 ++++ .../transactions/NFTokenBurn.h | 166 ++++ .../transactions/NFTokenCancelOffer.h | 129 +++ .../transactions/NFTokenCreateOffer.h | 264 +++++ .../transactions/NFTokenMint.h | 351 +++++++ .../transactions/NFTokenModify.h | 203 ++++ .../transactions/OfferCancel.h | 129 +++ .../transactions/OfferCreate.h | 264 +++++ .../transactions/OracleDelete.h | 129 +++ .../protocol_autogen/transactions/OracleSet.h | 288 ++++++ .../protocol_autogen/transactions/Payment.h | 416 ++++++++ .../transactions/PaymentChannelClaim.h | 314 ++++++ .../transactions/PaymentChannelCreate.h | 275 ++++++ .../transactions/PaymentChannelFund.h | 190 ++++ .../transactions/PermissionedDomainDelete.h | 129 +++ .../transactions/PermissionedDomainSet.h | 166 ++++ .../protocol_autogen/transactions/SetFee.h | 401 ++++++++ .../transactions/SetRegularKey.h | 142 +++ .../transactions/SignerListSet.h | 164 +++ .../transactions/TicketCreate.h | 129 +++ .../protocol_autogen/transactions/TrustSet.h | 216 ++++ .../protocol_autogen/transactions/UNLModify.h | 177 ++++ .../transactions/VaultClawback.h | 192 ++++ .../transactions/VaultCreate.h | 353 +++++++ .../transactions/VaultDelete.h | 129 +++ .../transactions/VaultDeposit.h | 155 +++ .../protocol_autogen/transactions/VaultSet.h | 240 +++++ .../transactions/VaultWithdraw.h | 229 +++++ .../transactions/XChainAccountCreateCommit.h | 201 ++++ .../XChainAddAccountCreateAttestation.h | 369 +++++++ .../transactions/XChainAddClaimAttestation.h | 358 +++++++ .../transactions/XChainClaim.h | 238 +++++ .../transactions/XChainCommit.h | 214 ++++ .../transactions/XChainCreateBridge.h | 190 ++++ .../transactions/XChainCreateClaimID.h | 177 ++++ .../transactions/XChainModifyBridge.h | 203 ++++ scripts/generate_ledger_classes.py | 227 +++++ scripts/generate_tx_classes.py | 247 +++++ scripts/macro_parser_common.py | 297 ++++++ scripts/requirements.txt | 13 + scripts/templates/LedgerEntry.h.mako | 216 ++++ scripts/templates/LedgerEntryTests.cpp.mako | 231 +++++ scripts/templates/Transaction.h.mako | 226 +++++ scripts/templates/TransactionTests.cpp.mako | 241 +++++ src/libxrpl/protocol_autogen/placeholder.cpp | 5 + src/tests/libxrpl/CMakeLists.txt | 15 + .../protocol_autogen/STObjectValidation.cpp | 70 ++ .../libxrpl/protocol_autogen/TestHelpers.h | 209 ++++ .../ledger_entries/AMMTests.cpp | 361 +++++++ .../ledger_entries/AccountRootTests.cpp | 707 +++++++++++++ .../ledger_entries/AmendmentsTests.cpp | 224 +++++ .../ledger_entries/BridgeTests.cpp | 341 +++++++ .../ledger_entries/CheckTests.cpp | 400 ++++++++ .../ledger_entries/CredentialTests.cpp | 329 +++++++ .../ledger_entries/DIDTests.cpp | 285 ++++++ .../ledger_entries/DelegateTests.cpp | 223 +++++ .../ledger_entries/DepositPreauthTests.cpp | 258 +++++ .../ledger_entries/DirectoryNodeTests.cpp | 484 +++++++++ .../ledger_entries/EscrowTests.cpp | 491 +++++++++ .../ledger_entries/FeeSettingsTests.cpp | 359 +++++++ .../ledger_entries/LedgerHashesTests.cpp | 192 ++++ .../ledger_entries/LoanBrokerTests.cpp | 530 ++++++++++ .../ledger_entries/LoanTests.cpp | 795 +++++++++++++++ .../ledger_entries/MPTokenIssuanceTests.cpp | 437 ++++++++ .../ledger_entries/MPTokenTests.cpp | 280 ++++++ .../ledger_entries/NFTokenOfferTests.cpp | 324 ++++++ .../ledger_entries/NFTokenPageTests.cpp | 236 +++++ .../ledger_entries/NegativeUNLTests.cpp | 251 +++++ .../ledger_entries/OfferTests.cpp | 395 ++++++++ .../ledger_entries/OracleTests.cpp | 346 +++++++ .../ledger_entries/PayChannelTests.cpp | 476 +++++++++ .../PermissionedDomainTests.cpp | 223 +++++ .../ledger_entries/RippleStateTests.cpp | 388 ++++++++ .../ledger_entries/SignerListTests.cpp | 275 ++++++ .../ledger_entries/TicketTests.cpp | 209 ++++ .../ledger_entries/VaultTests.cpp | 476 +++++++++ .../XChainOwnedClaimIDTests.cpp | 283 ++++++ .../XChainOwnedCreateAccountClaimIDTests.cpp | 243 +++++ src/tests/libxrpl/protocol_autogen/main.cpp | 8 + .../transactions/AMMBidTests.cpp | 255 +++++ .../transactions/AMMClawbackTests.cpp | 231 +++++ .../transactions/AMMCreateTests.cpp | 178 ++++ .../transactions/AMMDeleteTests.cpp | 162 +++ .../transactions/AMMDepositTests.cpp | 297 ++++++ .../transactions/AMMVoteTests.cpp | 178 ++++ .../transactions/AMMWithdrawTests.cpp | 276 ++++++ .../transactions/AccountDeleteTests.cpp | 216 ++++ .../transactions/AccountSetTests.cpp | 366 +++++++ .../transactions/BatchTests.cpp | 195 ++++ .../transactions/CheckCancelTests.cpp | 146 +++ .../transactions/CheckCashTests.cpp | 216 ++++ .../transactions/CheckCreateTests.cpp | 255 +++++ .../transactions/ClawbackTests.cpp | 195 ++++ .../transactions/CredentialAcceptTests.cpp | 162 +++ .../transactions/CredentialCreateTests.cpp | 234 +++++ .../transactions/CredentialDeleteTests.cpp | 216 ++++ .../transactions/DIDDeleteTests.cpp | 130 +++ .../transactions/DIDSetTests.cpp | 219 +++++ .../transactions/DelegateSetTests.cpp | 162 +++ .../transactions/DepositPreauthTests.cpp | 240 +++++ .../transactions/EnableAmendmentTests.cpp | 162 +++ .../transactions/EscrowCancelTests.cpp | 162 +++ .../transactions/EscrowCreateTests.cpp | 276 ++++++ .../transactions/EscrowFinishTests.cpp | 255 +++++ .../transactions/LedgerStateFixTests.cpp | 195 ++++ .../LoanBrokerCoverClawbackTests.cpp | 198 ++++ .../LoanBrokerCoverDepositTests.cpp | 162 +++ .../LoanBrokerCoverWithdrawTests.cpp | 234 +++++ .../transactions/LoanBrokerDeleteTests.cpp | 146 +++ .../transactions/LoanBrokerSetTests.cpp | 300 ++++++ .../transactions/LoanDeleteTests.cpp | 146 +++ .../transactions/LoanManageTests.cpp | 146 +++ .../transactions/LoanPayTests.cpp | 162 +++ .../transactions/LoanSetTests.cpp | 507 ++++++++++ .../transactions/MPTokenAuthorizeTests.cpp | 195 ++++ .../MPTokenIssuanceCreateTests.cpp | 282 ++++++ .../MPTokenIssuanceDestroyTests.cpp | 146 +++ .../transactions/MPTokenIssuanceSetTests.cpp | 279 ++++++ .../transactions/NFTokenAcceptOfferTests.cpp | 219 +++++ .../transactions/NFTokenBurnTests.cpp | 195 ++++ .../transactions/NFTokenCancelOfferTests.cpp | 146 +++ .../transactions/NFTokenCreateOfferTests.cpp | 255 +++++ .../transactions/NFTokenMintTests.cpp | 300 ++++++ .../transactions/NFTokenModifyTests.cpp | 216 ++++ .../transactions/OfferCancelTests.cpp | 146 +++ .../transactions/OfferCreateTests.cpp | 255 +++++ .../transactions/OracleDeleteTests.cpp | 146 +++ .../transactions/OracleSetTests.cpp | 273 +++++ .../transactions/PaymentChannelClaimTests.cpp | 279 ++++++ .../PaymentChannelCreateTests.cpp | 270 +++++ .../transactions/PaymentChannelFundTests.cpp | 213 ++++ .../transactions/PaymentTests.cpp | 339 +++++++ .../PermissionedDomainDeleteTests.cpp | 146 +++ .../PermissionedDomainSetTests.cpp | 195 ++++ .../transactions/SetFeeTests.cpp | 324 ++++++ .../transactions/SetRegularKeyTests.cpp | 177 ++++ .../transactions/SignerListSetTests.cpp | 195 ++++ .../transactions/TicketCreateTests.cpp | 146 +++ .../transactions/TrustSetTests.cpp | 219 +++++ .../transactions/UNLModifyTests.cpp | 178 ++++ .../transactions/VaultClawbackTests.cpp | 213 ++++ .../transactions/VaultCreateTests.cpp | 300 ++++++ .../transactions/VaultDeleteTests.cpp | 146 +++ .../transactions/VaultDepositTests.cpp | 162 +++ .../transactions/VaultSetTests.cpp | 237 +++++ .../transactions/VaultWithdrawTests.cpp | 234 +++++ .../XChainAccountCreateCommitTests.cpp | 194 ++++ ...XChainAddAccountCreateAttestationTests.cpp | 306 ++++++ .../XChainAddClaimAttestationTests.cpp | 339 +++++++ .../transactions/XChainClaimTests.cpp | 249 +++++ .../transactions/XChainCommitTests.cpp | 231 +++++ .../transactions/XChainCreateBridgeTests.cpp | 213 ++++ .../transactions/XChainCreateClaimIDTests.cpp | 178 ++++ .../transactions/XChainModifyBridgeTests.cpp | 216 ++++ 237 files changed, 59363 insertions(+), 5 deletions(-) create mode 100644 cmake/XrplProtocolAutogen.cmake create mode 100644 include/xrpl/protocol_autogen/LedgerEntryBase.h create mode 100644 include/xrpl/protocol_autogen/LedgerEntryBuilderBase.h create mode 100644 include/xrpl/protocol_autogen/README.md create mode 100644 include/xrpl/protocol_autogen/STObjectValidation.h create mode 100644 include/xrpl/protocol_autogen/TransactionBase.h create mode 100644 include/xrpl/protocol_autogen/TransactionBuilderBase.h create mode 100644 include/xrpl/protocol_autogen/Utils.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/AMM.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/AccountRoot.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Amendments.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Bridge.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Check.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Credential.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/DID.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Delegate.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/DepositPreauth.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/DirectoryNode.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Escrow.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/FeeSettings.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/LedgerHashes.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Loan.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/LoanBroker.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/MPToken.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/MPTokenIssuance.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/NFTokenOffer.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/NFTokenPage.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/NegativeUNL.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Offer.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Oracle.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/PayChannel.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/PermissionedDomain.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/RippleState.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/SignerList.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Ticket.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/Vault.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h create mode 100644 include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMBid.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMClawback.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMDeposit.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMVote.h create mode 100644 include/xrpl/protocol_autogen/transactions/AMMWithdraw.h create mode 100644 include/xrpl/protocol_autogen/transactions/AccountDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/AccountSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/Batch.h create mode 100644 include/xrpl/protocol_autogen/transactions/CheckCancel.h create mode 100644 include/xrpl/protocol_autogen/transactions/CheckCash.h create mode 100644 include/xrpl/protocol_autogen/transactions/CheckCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/Clawback.h create mode 100644 include/xrpl/protocol_autogen/transactions/CredentialAccept.h create mode 100644 include/xrpl/protocol_autogen/transactions/CredentialCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/CredentialDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/DIDDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/DIDSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/DelegateSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/DepositPreauth.h create mode 100644 include/xrpl/protocol_autogen/transactions/EnableAmendment.h create mode 100644 include/xrpl/protocol_autogen/transactions/EscrowCancel.h create mode 100644 include/xrpl/protocol_autogen/transactions/EscrowCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/EscrowFinish.h create mode 100644 include/xrpl/protocol_autogen/transactions/LedgerStateFix.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanBrokerCoverClawback.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanBrokerCoverDeposit.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanBrokerCoverWithdraw.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanBrokerDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanBrokerSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanManage.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanPay.h create mode 100644 include/xrpl/protocol_autogen/transactions/LoanSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/MPTokenAuthorize.h create mode 100644 include/xrpl/protocol_autogen/transactions/MPTokenIssuanceCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/MPTokenIssuanceDestroy.h create mode 100644 include/xrpl/protocol_autogen/transactions/MPTokenIssuanceSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/NFTokenAcceptOffer.h create mode 100644 include/xrpl/protocol_autogen/transactions/NFTokenBurn.h create mode 100644 include/xrpl/protocol_autogen/transactions/NFTokenCancelOffer.h create mode 100644 include/xrpl/protocol_autogen/transactions/NFTokenCreateOffer.h create mode 100644 include/xrpl/protocol_autogen/transactions/NFTokenMint.h create mode 100644 include/xrpl/protocol_autogen/transactions/NFTokenModify.h create mode 100644 include/xrpl/protocol_autogen/transactions/OfferCancel.h create mode 100644 include/xrpl/protocol_autogen/transactions/OfferCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/OracleDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/OracleSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/Payment.h create mode 100644 include/xrpl/protocol_autogen/transactions/PaymentChannelClaim.h create mode 100644 include/xrpl/protocol_autogen/transactions/PaymentChannelCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/PaymentChannelFund.h create mode 100644 include/xrpl/protocol_autogen/transactions/PermissionedDomainDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/PermissionedDomainSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/SetFee.h create mode 100644 include/xrpl/protocol_autogen/transactions/SetRegularKey.h create mode 100644 include/xrpl/protocol_autogen/transactions/SignerListSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/TicketCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/TrustSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/UNLModify.h create mode 100644 include/xrpl/protocol_autogen/transactions/VaultClawback.h create mode 100644 include/xrpl/protocol_autogen/transactions/VaultCreate.h create mode 100644 include/xrpl/protocol_autogen/transactions/VaultDelete.h create mode 100644 include/xrpl/protocol_autogen/transactions/VaultDeposit.h create mode 100644 include/xrpl/protocol_autogen/transactions/VaultSet.h create mode 100644 include/xrpl/protocol_autogen/transactions/VaultWithdraw.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainClaim.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainCommit.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h create mode 100644 include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h create mode 100644 scripts/generate_ledger_classes.py create mode 100644 scripts/generate_tx_classes.py create mode 100644 scripts/macro_parser_common.py create mode 100644 scripts/requirements.txt create mode 100644 scripts/templates/LedgerEntry.h.mako create mode 100644 scripts/templates/LedgerEntryTests.cpp.mako create mode 100644 scripts/templates/Transaction.h.mako create mode 100644 scripts/templates/TransactionTests.cpp.mako create mode 100644 src/libxrpl/protocol_autogen/placeholder.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/STObjectValidation.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/TestHelpers.h create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/AMMTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/AccountRootTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/AmendmentsTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/CheckTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/CredentialTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/DIDTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/DelegateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/DepositPreauthTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/DirectoryNodeTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/EscrowTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/FeeSettingsTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/LedgerHashesTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/LoanBrokerTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenIssuanceTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenOfferTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenPageTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/NegativeUNLTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/OfferTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/OracleTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/PayChannelTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/PermissionedDomainTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/RippleStateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/SignerListTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/TicketTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/main.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMBidTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMClawbackTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMDepositTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMVoteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AMMWithdrawTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AccountDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/AccountSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/BatchTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/CheckCancelTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/CheckCashTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/CheckCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/ClawbackTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/CredentialAcceptTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/CredentialCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/CredentialDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/DIDDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/DIDSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/DelegateSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/DepositPreauthTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/EnableAmendmentTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/EscrowCancelTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/EscrowCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/EscrowFinishTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LedgerStateFixTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverClawbackTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverDepositTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverWithdrawTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanManageTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanPayTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/LoanSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/MPTokenAuthorizeTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceDestroyTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/NFTokenAcceptOfferTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/NFTokenBurnTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/NFTokenCancelOfferTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/NFTokenCreateOfferTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/NFTokenMintTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/NFTokenModifyTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/OfferCancelTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/OfferCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/OracleDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/OracleSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelClaimTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelFundTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/PaymentTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/SetFeeTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/SetRegularKeyTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/SignerListSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/TicketCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/TrustSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/UNLModifyTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/VaultClawbackTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/VaultCreateTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/VaultDeleteTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/VaultDepositTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/VaultSetTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/VaultWithdrawTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp create mode 100644 src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp diff --git a/.gersemi/definitions.cmake b/.gersemi/definitions.cmake index 13061629a4..a16e330ffa 100644 --- a/.gersemi/definitions.cmake +++ b/.gersemi/definitions.cmake @@ -51,6 +51,9 @@ endfunction() function(add_module parent name) endfunction() +function(setup_protocol_autogen) +endfunction() + function(target_link_modules parent scope) endfunction() diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 747ea8b6a6..d26a5a1963 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -19,6 +19,7 @@ libxrpl.nodestore > xrpl.protocol libxrpl.protocol > xrpl.basics libxrpl.protocol > xrpl.json libxrpl.protocol > xrpl.protocol +libxrpl.protocol_autogen > xrpl.protocol_autogen libxrpl.rdb > xrpl.basics libxrpl.rdb > xrpl.rdb libxrpl.resource > xrpl.basics @@ -176,6 +177,8 @@ test.unit_test > xrpl.protocol tests.libxrpl > xrpl.basics tests.libxrpl > xrpl.json tests.libxrpl > xrpl.net +tests.libxrpl > xrpl.protocol +tests.libxrpl > xrpl.protocol_autogen xrpl.conditions > xrpl.basics xrpl.conditions > xrpl.protocol xrpl.core > xrpl.basics @@ -192,6 +195,8 @@ xrpl.nodestore > xrpl.basics xrpl.nodestore > xrpl.protocol xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.json +xrpl.protocol_autogen > xrpl.json +xrpl.protocol_autogen > xrpl.protocol xrpl.rdb > xrpl.basics xrpl.rdb > xrpl.core xrpl.rdb > xrpl.protocol diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index efec2afe0a..6e7a093b96 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -166,6 +166,29 @@ jobs: --parallel "${BUILD_NPROC}" \ --target "${CMAKE_TARGET}" + - name: Check protocol autogen files are up-to-date + env: + MESSAGE: | + + The generated protocol wrapper classes are out of date. + + This typically happens when your branch is behind develop and + the macro files or generator scripts have changed. + + To fix this: + 1. Update your branch from develop (merge or rebase) + 2. Build with code generation enabled (XRPL_NO_CODEGEN=OFF) + 3. Commit and push the regenerated files + run: | + set -e + DIFF=$(git status --porcelain -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen) + if [ -n "${DIFF}" ]; then + echo "::error::Generated protocol files are out of date" + git diff -- include/xrpl/protocol_autogen src/tests/libxrpl/protocol_autogen + echo "${MESSAGE}" + exit 1 + fi + - name: Show ccache statistics if: ${{ inputs.ccache_enabled }} run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 586cfe860c..0fcd8ca75d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,8 +14,11 @@ repos: rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: trailing-whitespace + exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - id: end-of-file-fixer + exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - id: mixed-line-ending + exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - id: check-merge-conflict args: [--assume-in-merge] @@ -25,6 +28,7 @@ repos: - id: clang-format args: [--style=file] "types_or": [c++, c, proto] + exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - repo: https://github.com/BlankSpruce/gersemi rev: 0.26.0 @@ -45,7 +49,7 @@ repos: rev: a42085ade523f591dca134379a595e7859986445 # frozen: v9.7.0 hooks: - id: cspell # Spell check changed files - exclude: .config/cspell.config.yaml + exclude: (.config/cspell.config.yaml|^include/xrpl/protocol_autogen/(transactions|ledger_entries)/) - id: cspell # Spell check the commit message name: check commit message spelling args: @@ -77,5 +81,6 @@ repos: exclude: | (?x)^( external/.*| - .github/scripts/levelization/results/.*\.txt + .github/scripts/levelization/results/.*\.txt| + src/tests/libxrpl/protocol_autogen/(transactions|ledger_entries)/.* )$ diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index 580c4155eb..a50e30f660 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -108,17 +108,40 @@ target_link_libraries( ) # Level 05 +## Set up code generation for protocol_autogen module +include(XrplProtocolAutogen) +# Must call setup_protocol_autogen before add_module so that: +# 1. Stale generated files are cleared before GLOB runs +# 2. Output file list is known for custom commands +setup_protocol_autogen() + +add_module(xrpl protocol_autogen) +target_link_libraries( + xrpl.libxrpl.protocol_autogen + PUBLIC xrpl.libxrpl.protocol +) + +# Ensure code generation runs before compiling protocol_autogen +if(TARGET protocol_autogen_generate) + add_dependencies(xrpl.libxrpl.protocol_autogen protocol_autogen_generate) +endif() + +# Level 06 add_module(xrpl core) target_link_libraries( xrpl.libxrpl.core - PUBLIC xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol + PUBLIC + xrpl.libxrpl.basics + xrpl.libxrpl.json + xrpl.libxrpl.protocol + xrpl.libxrpl.protocol_autogen ) -# Level 06 +# Level 07 add_module(xrpl resource) target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol) -# Level 07 +# Level 08 add_module(xrpl net) target_link_libraries( xrpl.libxrpl.net @@ -171,6 +194,7 @@ target_link_libraries( xrpl.libxrpl.basics xrpl.libxrpl.json xrpl.libxrpl.protocol + xrpl.libxrpl.protocol_autogen xrpl.libxrpl.rdb xrpl.libxrpl.server xrpl.libxrpl.shamap @@ -206,6 +230,7 @@ target_link_modules( net nodestore protocol + protocol_autogen rdb resource server diff --git a/cmake/XrplProtocolAutogen.cmake b/cmake/XrplProtocolAutogen.cmake new file mode 100644 index 0000000000..44857712cd --- /dev/null +++ b/cmake/XrplProtocolAutogen.cmake @@ -0,0 +1,287 @@ +#[===================================================================[ + Protocol Autogen - Code generation for protocol wrapper classes +#]===================================================================] + +# Options for code generation +option( + XRPL_NO_CODEGEN + "Disable code generation (use pre-generated files from repository)" + OFF +) +set(CODEGEN_VENV_DIR + "" + CACHE PATH + "Path to Python virtual environment for code generation. If provided, automatic venv setup is skipped." +) + +# Function to set up code generation for protocol_autogen module +# This runs at configure time to generate C++ wrapper classes from macro files +function(setup_protocol_autogen) + # Directory paths + set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl/protocol/detail") + set(AUTOGEN_HEADER_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl/protocol_autogen" + ) + set(AUTOGEN_TEST_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/src/tests/libxrpl/protocol_autogen" + ) + set(SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") + + # Input macro files + set(TRANSACTIONS_MACRO "${MACRO_DIR}/transactions.macro") + set(LEDGER_ENTRIES_MACRO "${MACRO_DIR}/ledger_entries.macro") + set(SFIELDS_MACRO "${MACRO_DIR}/sfields.macro") + + # Python scripts and templates + set(GENERATE_TX_SCRIPT "${SCRIPTS_DIR}/generate_tx_classes.py") + set(GENERATE_LEDGER_SCRIPT "${SCRIPTS_DIR}/generate_ledger_classes.py") + set(REQUIREMENTS_FILE "${SCRIPTS_DIR}/requirements.txt") + set(MACRO_PARSER_COMMON "${SCRIPTS_DIR}/macro_parser_common.py") + set(TX_TEMPLATE "${SCRIPTS_DIR}/templates/Transaction.h.mako") + set(TX_TEST_TEMPLATE "${SCRIPTS_DIR}/templates/TransactionTests.cpp.mako") + set(LEDGER_TEMPLATE "${SCRIPTS_DIR}/templates/LedgerEntry.h.mako") + set(LEDGER_TEST_TEMPLATE + "${SCRIPTS_DIR}/templates/LedgerEntryTests.cpp.mako" + ) + + # Check if code generation is disabled + if(XRPL_NO_CODEGEN) + message( + WARNING + "Protocol autogen: Code generation is disabled (XRPL_NO_CODEGEN=ON). " + "Generated files may be out of date." + ) + return() + endif() + + # Create output directories + file(MAKE_DIRECTORY "${AUTOGEN_HEADER_DIR}/transactions") + file(MAKE_DIRECTORY "${AUTOGEN_HEADER_DIR}/ledger_entries") + file(MAKE_DIRECTORY "${AUTOGEN_TEST_DIR}/ledger_entries") + file(MAKE_DIRECTORY "${AUTOGEN_TEST_DIR}/transactions") + + # Find Python3 - check if already found by Conan or find it ourselves + if(NOT Python3_EXECUTABLE) + find_package(Python3 COMPONENTS Interpreter QUIET) + endif() + + if(NOT Python3_EXECUTABLE) + # Try finding python3 executable directly + find_program(Python3_EXECUTABLE NAMES python3 python) + endif() + + if(NOT Python3_EXECUTABLE) + message( + FATAL_ERROR + "Python3 not found. Code generation cannot proceed.\n" + "Please install Python 3, or set -DXRPL_NO_CODEGEN=ON to use existing generated files." + ) + return() + endif() + + message(STATUS "Using Python3 for code generation: ${Python3_EXECUTABLE}") + + # Set up Python virtual environment for code generation + if(CODEGEN_VENV_DIR) + # User-provided venv - skip automatic setup + set(VENV_DIR "${CODEGEN_VENV_DIR}") + message(STATUS "Using user-provided Python venv: ${VENV_DIR}") + else() + # Use default venv in build directory + set(VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/codegen_venv") + endif() + + # Determine the Python executable path in the venv + if(WIN32) + set(VENV_PYTHON "${VENV_DIR}/Scripts/python.exe") + set(VENV_PIP "${VENV_DIR}/Scripts/pip.exe") + else() + set(VENV_PYTHON "${VENV_DIR}/bin/python") + set(VENV_PIP "${VENV_DIR}/bin/pip") + endif() + + # Only auto-setup venv if not user-provided + if(NOT CODEGEN_VENV_DIR) + # Check if venv needs to be created or updated + set(VENV_NEEDS_UPDATE FALSE) + if(NOT EXISTS "${VENV_PYTHON}") + set(VENV_NEEDS_UPDATE TRUE) + message( + STATUS + "Creating Python virtual environment for code generation..." + ) + elseif( + "${REQUIREMENTS_FILE}" + IS_NEWER_THAN + "${VENV_DIR}/.requirements_installed" + ) + set(VENV_NEEDS_UPDATE TRUE) + message( + STATUS + "Updating Python virtual environment (requirements changed)..." + ) + endif() + + # Create/update virtual environment if needed + if(VENV_NEEDS_UPDATE) + message( + STATUS + "Setting up Python virtual environment at ${VENV_DIR}" + ) + execute_process( + COMMAND ${Python3_EXECUTABLE} -m venv "${VENV_DIR}" + RESULT_VARIABLE VENV_RESULT + ERROR_VARIABLE VENV_ERROR + ) + if(NOT VENV_RESULT EQUAL 0) + message( + FATAL_ERROR + "Failed to create virtual environment: ${VENV_ERROR}" + ) + endif() + + message(STATUS "Installing Python dependencies...") + execute_process( + COMMAND ${VENV_PIP} install --upgrade pip + RESULT_VARIABLE PIP_UPGRADE_RESULT + OUTPUT_QUIET + ERROR_VARIABLE PIP_UPGRADE_ERROR + ) + if(NOT PIP_UPGRADE_RESULT EQUAL 0) + message(WARNING "Failed to upgrade pip: ${PIP_UPGRADE_ERROR}") + endif() + + execute_process( + COMMAND ${VENV_PIP} install -r "${REQUIREMENTS_FILE}" + RESULT_VARIABLE PIP_INSTALL_RESULT + ERROR_VARIABLE PIP_INSTALL_ERROR + ) + if(NOT PIP_INSTALL_RESULT EQUAL 0) + message( + FATAL_ERROR + "Failed to install Python dependencies: ${PIP_INSTALL_ERROR}" + ) + endif() + + # Mark requirements as installed + file(TOUCH "${VENV_DIR}/.requirements_installed") + message(STATUS "Python virtual environment ready") + endif() + endif() + + # At configure time - get list of output files for transactions + execute_process( + COMMAND + ${VENV_PYTHON} "${GENERATE_TX_SCRIPT}" "${TRANSACTIONS_MACRO}" + --header-dir "${AUTOGEN_HEADER_DIR}/transactions" --test-dir + "${AUTOGEN_TEST_DIR}/transactions" --list-outputs + OUTPUT_VARIABLE TX_OUTPUT_FILES + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE TX_LIST_RESULT + ERROR_VARIABLE TX_LIST_ERROR + ) + if(NOT TX_LIST_RESULT EQUAL 0) + message( + FATAL_ERROR + "Failed to list transaction output files:\n${TX_LIST_ERROR}" + ) + endif() + # Convert newline-separated list to CMake list + string(REPLACE "\\" "/" TX_OUTPUT_FILES "${TX_OUTPUT_FILES}") + string(REPLACE "\n" ";" TX_OUTPUT_FILES "${TX_OUTPUT_FILES}") + + # At configure time - get list of output files for ledger entries + execute_process( + COMMAND + ${VENV_PYTHON} "${GENERATE_LEDGER_SCRIPT}" "${LEDGER_ENTRIES_MACRO}" + --header-dir "${AUTOGEN_HEADER_DIR}/ledger_entries" --test-dir + "${AUTOGEN_TEST_DIR}/ledger_entries" --list-outputs + OUTPUT_VARIABLE LEDGER_OUTPUT_FILES + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE LEDGER_LIST_RESULT + ERROR_VARIABLE LEDGER_LIST_ERROR + ) + if(NOT LEDGER_LIST_RESULT EQUAL 0) + message( + FATAL_ERROR + "Failed to list ledger entry output files:\n${LEDGER_LIST_ERROR}" + ) + endif() + # Convert newline-separated list to CMake list + string(REPLACE "\\" "/" LEDGER_OUTPUT_FILES "${LEDGER_OUTPUT_FILES}") + string(REPLACE "\n" ";" LEDGER_OUTPUT_FILES "${LEDGER_OUTPUT_FILES}") + + # Custom command to generate transaction classes at build time + add_custom_command( + OUTPUT ${TX_OUTPUT_FILES} + COMMAND + ${VENV_PYTHON} "${GENERATE_TX_SCRIPT}" "${TRANSACTIONS_MACRO}" + --header-dir "${AUTOGEN_HEADER_DIR}/transactions" --test-dir + "${AUTOGEN_TEST_DIR}/transactions" --sfields-macro + "${SFIELDS_MACRO}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DEPENDS + "${TRANSACTIONS_MACRO}" + "${SFIELDS_MACRO}" + "${GENERATE_TX_SCRIPT}" + "${MACRO_PARSER_COMMON}" + "${TX_TEMPLATE}" + "${TX_TEST_TEMPLATE}" + "${REQUIREMENTS_FILE}" + COMMENT "Generating transaction classes from transactions.macro..." + VERBATIM + ) + + # Custom command to generate ledger entry classes at build time + add_custom_command( + OUTPUT ${LEDGER_OUTPUT_FILES} + COMMAND + ${VENV_PYTHON} "${GENERATE_LEDGER_SCRIPT}" "${LEDGER_ENTRIES_MACRO}" + --header-dir "${AUTOGEN_HEADER_DIR}/ledger_entries" --test-dir + "${AUTOGEN_TEST_DIR}/ledger_entries" --sfields-macro + "${SFIELDS_MACRO}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DEPENDS + "${LEDGER_ENTRIES_MACRO}" + "${SFIELDS_MACRO}" + "${GENERATE_LEDGER_SCRIPT}" + "${MACRO_PARSER_COMMON}" + "${LEDGER_TEMPLATE}" + "${LEDGER_TEST_TEMPLATE}" + "${REQUIREMENTS_FILE}" + COMMENT "Generating ledger entry classes from ledger_entries.macro..." + VERBATIM + ) + + # Create a custom target that depends on all generated files + add_custom_target( + protocol_autogen_generate + DEPENDS ${TX_OUTPUT_FILES} ${LEDGER_OUTPUT_FILES} + COMMENT "Protocol autogen code generation" + ) + + # Extract test files from output lists (files ending in Tests.cpp) + set(PROTOCOL_AUTOGEN_TEST_SOURCES "") + foreach(FILE ${TX_OUTPUT_FILES} ${LEDGER_OUTPUT_FILES}) + if(FILE MATCHES "Tests\\.cpp$") + list(APPEND PROTOCOL_AUTOGEN_TEST_SOURCES "${FILE}") + endif() + endforeach() + # Export test sources to parent scope for use in test CMakeLists.txt + set(PROTOCOL_AUTOGEN_TEST_SOURCES + "${PROTOCOL_AUTOGEN_TEST_SOURCES}" + CACHE INTERNAL + "Generated protocol_autogen test sources" + ) + + # Register dependencies so CMake reconfigures when macro files change + # (to update the list of output files) + set_property( + DIRECTORY + APPEND + PROPERTY + CMAKE_CONFIGURE_DEPENDS + "${TRANSACTIONS_MACRO}" + "${LEDGER_ENTRIES_MACRO}" + ) +endfunction() diff --git a/cspell.config.yaml b/cspell.config.yaml index eeae3d12ff..d1b8504021 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -206,6 +206,7 @@ words: - ptrs - pushd - pyenv + - pyparsing - qalloc - queuable - Raphson @@ -231,6 +232,7 @@ words: - seqit - sf - SFIELD + - sfields - shamap - shamapitem - sidechain diff --git a/include/xrpl/protocol_autogen/LedgerEntryBase.h b/include/xrpl/protocol_autogen/LedgerEntryBase.h new file mode 100644 index 0000000000..0c5b367391 --- /dev/null +++ b/include/xrpl/protocol_autogen/LedgerEntryBase.h @@ -0,0 +1,152 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +/** + * @brief Base class for type-safe ledger entry wrappers. + * + * This class provides common functionality for all ledger entry types, + * including access to common fields (sfLedgerIndex, sfLedgerEntryType, sfFlags). + * + * This is an immutable wrapper around SLE (Serialized Ledger Entry). + * Use the corresponding Builder classes to construct new ledger entries. + */ +class LedgerEntryBase +{ +public: + /** + * @brief Construct a ledger entry wrapper from an existing SLE object. + * @param sle The underlying serialized ledger entry to wrap + */ + explicit LedgerEntryBase(std::shared_ptr sle) : sle_(std::move(sle)) + { + } + + /** + * @brief Validate the ledger entry + * @return true if validation passes, false otherwise + */ + [[nodiscard]] + bool + validate() const + { + if (!sle_->isFieldPresent(sfLedgerEntryType)) + { + return false; // LCOV_EXCL_LINE + } + auto ledgerEntryType = static_cast(sle_->getFieldU16(sfLedgerEntryType)); + return protocol_autogen::validateSTObject( + *sle_, LedgerFormats::getInstance().findByType(ledgerEntryType)->getSOTemplate()); + } + + /** + * @brief Get the ledger entry type. + * @return The type of this ledger entry + */ + [[nodiscard]] + LedgerEntryType + getType() const + { + return sle_->getType(); + } + + /** + * @brief Get the key (index) of this ledger entry. + * + * The key uniquely identifies this ledger entry in the ledger state. + * @return A constant reference to the 256-bit key + */ + [[nodiscard]] + uint256 const& + getKey() const + { + return sle_->key(); + } + + // Common field getters (from LedgerFormats.cpp commonFields) + + /** + * @brief Get the ledger index (sfLedgerIndex). + * + * This field is OPTIONAL and represents the index of the ledger entry. + * @return The ledger index if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getLedgerIndex() const + { + if (sle_->isFieldPresent(sfLedgerIndex)) + { + return sle_->at(sfLedgerIndex); + } + return std::nullopt; + } + + /** + * @brief Check if the ledger entry has a ledger index. + * @return true if sfLedgerIndex is present, false otherwise + */ + [[nodiscard]] + bool + hasLedgerIndex() const + { + return sle_->isFieldPresent(sfLedgerIndex); + } + + /** + * @brief Get the ledger entry type field (sfLedgerEntryType). + * + * This field is REQUIRED for all ledger entries and indicates the type + * of the ledger entry (e.g., AccountRoot, RippleState, Offer, etc.). + * @return The ledger entry type as a 16-bit unsigned integer + */ + [[nodiscard]] + uint16_t + getLedgerEntryType() const + { + return sle_->at(sfLedgerEntryType); + } + + /** + * @brief Get the flags field (sfFlags). + * + * This field is REQUIRED for all ledger entries and contains + * type-specific flags that modify the behavior of the ledger entry. + * @return The flags value as a 32-bit unsigned integer + */ + [[nodiscard]] + std::uint32_t + getFlags() const + { + return sle_->at(sfFlags); + } + + /** + * @brief Get the underlying SLE object. + * + * Provides direct access to the wrapped serialized ledger entry object + * for cases where the type-safe accessors are insufficient. + * @return A constant reference to the underlying SLE object + */ + [[nodiscard]] + std::shared_ptr + getSle() const + { + return sle_; + } + +protected: + /** @brief The underlying serialized ledger entry being wrapped. */ + std::shared_ptr sle_; +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/LedgerEntryBuilderBase.h b/include/xrpl/protocol_autogen/LedgerEntryBuilderBase.h new file mode 100644 index 0000000000..e2f05c31ab --- /dev/null +++ b/include/xrpl/protocol_autogen/LedgerEntryBuilderBase.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xrpl::ledger_entries { + +/** + * Base class for all ledger entry builders. + * Provides common field setters that are available for all ledger entry types. + */ +template +class LedgerEntryBuilderBase +{ +public: + LedgerEntryBuilderBase() = default; + + LedgerEntryBuilderBase( + SF_UINT16::type::value_type ledgerEntryType, + SF_UINT32::type::value_type flags = 0) + { + // Don't call object_.set(soTemplate) - keep object_ as a free object. + // This avoids creating STBase placeholders for soeDEFAULT fields, + // which would cause applyTemplate() to throw "may not be explicitly + // set to default" when building the SLE. + // The SLE constructor will call applyTemplate() which properly + // handles missing fields. + object_[sfLedgerEntryType] = ledgerEntryType; + object_[sfFlags] = flags; + } + + /** + * @brief Validate the ledger entry + * @return true if validation passes, false otherwise + */ + [[nodiscard]] + bool + validate() const + { + if (!object_.isFieldPresent(sfLedgerEntryType)) + { + return false; // LCOV_EXCL_LINE + } + auto ledgerEntryType = static_cast(object_.getFieldU16(sfLedgerEntryType)); + return protocol_autogen::validateSTObject( + object_, LedgerFormats::getInstance().findByType(ledgerEntryType)->getSOTemplate()); + } + + /** + * Set the ledger index. + * @param value Ledger index + * @return Reference to the derived builder for method chaining. + */ + Derived& + setLedgerIndex(uint256 const& value) + { + object_[sfLedgerIndex] = value; + return static_cast(*this); + } + + /** + * Set the flags. + * @param value Flags value + * @return Reference to the derived builder for method chaining. + */ + Derived& + setFlags(uint32_t value) + { + object_.setFieldU32(sfFlags, value); + return static_cast(*this); + } + +protected: + STObject object_{sfLedgerEntry}; +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/README.md b/include/xrpl/protocol_autogen/README.md new file mode 100644 index 0000000000..be90788b05 --- /dev/null +++ b/include/xrpl/protocol_autogen/README.md @@ -0,0 +1,79 @@ +# Protocol Autogen + +This directory contains auto-generated C++ wrapper classes for XRP Ledger protocol types. + +## Generated Files + +The files in this directory are automatically generated at **CMake configure time** from macro definition files: + +- **Transaction classes** (in `transactions/`): Generated from `include/xrpl/protocol/detail/transactions.macro` by `scripts/generate_tx_classes.py` +- **Ledger entry classes** (in `ledger_entries/`): Generated from `include/xrpl/protocol/detail/ledger_entries.macro` by `scripts/generate_ledger_classes.py` + +## Generation Process + +The generation happens automatically when you **configure** the project (not during build). When you run CMake, the system: + +1. Creates a Python virtual environment in the build directory (`codegen_venv`) +2. Installs Python dependencies from `scripts/requirements.txt` into the venv (only if needed) +3. Runs the Python generation scripts using the venv Python interpreter +4. Parses the macro files to extract type definitions +5. Generates type-safe C++ wrapper classes using Mako templates +6. Places the generated headers in this directory + +### When Regeneration Happens + +The code is regenerated when: + +- You run CMake configure for the first time +- The Python virtual environment doesn't exist +- `scripts/requirements.txt` has been modified + +To force regeneration, delete the build directory and reconfigure. + +### Python Dependencies + +The code generation requires the following Python packages (automatically installed): + +- `pcpp` - C preprocessor for Python +- `pyparsing` - Parser combinator library +- `Mako` - Template engine + +These are isolated in a virtual environment and won't affect your system Python installation. + +## Version Control + +The generated `.h` files **are checked into version control**. This means: + +- Developers without Python 3 can still build the project using the committed files +- CI/CD systems don't need to run code generation if files are up to date +- Changes to generated files are visible in code review + +## Modifying Generated Code + +**Do not manually edit generated files.** Any changes will be overwritten the next time CMake configure runs. + +To modify the generated classes: + +- Edit the macro files in `include/xrpl/protocol/detail/` +- Edit the Mako templates in `scripts/templates/` +- Edit the generation scripts in `scripts/` +- Update Python dependencies in `scripts/requirements.txt` +- Run CMake configure to regenerate + +## Adding Common Fields + +If you add a new common field to `TxFormats.cpp` or `LedgerFormats.cpp`, you should also update the corresponding base classes and templates manually: + +Base classes: + +- `TransactionBase.h` - Add getters for new common transaction fields +- `TransactionBuilderBase.h` - Add setters, and if the field is required, add it to the constructor parameters +- `LedgerEntryBase.h` - Add getters for new common ledger entry fields +- `LedgerEntryBuilderBase.h` - Add setters, and if the field is required, add it to the constructor parameters + +Templates (update to pass required common fields to base class constructors): + +- `scripts/templates/Transaction.h.mako` +- `scripts/templates/LedgerEntry.h.mako` + +These files are **not auto-generated** and must be updated by hand. diff --git a/include/xrpl/protocol_autogen/STObjectValidation.h b/include/xrpl/protocol_autogen/STObjectValidation.h new file mode 100644 index 0000000000..cd0633af5d --- /dev/null +++ b/include/xrpl/protocol_autogen/STObjectValidation.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace xrpl::protocol_autogen { + +[[nodiscard]] +inline bool +validateSTObject(STObject const& obj, SOTemplate const& format) +{ + for (auto const& field : format) + { + if (!obj.isFieldPresent(field.sField()) && field.style() == soeREQUIRED) + { + return false; // LCOV_EXCL_LINE + } + + if (field.supportMPT() == soeMPTNotSupported && obj.isFieldPresent(field.sField())) + { + if (field.sField().fieldType == STI_AMOUNT) + { + auto const& amount = obj.getFieldAmount(field.sField()); + + if (amount.asset().holds()) + return false; // LCOV_EXCL_LINE + } + else if (field.sField().fieldType == STI_ISSUE) + { + auto issue = dynamic_cast(obj.peekAtPField(field.sField())); + if (!issue) + return false; // LCOV_EXCL_LINE + + if (issue->holds()) + return false; // LCOV_EXCL_LINE + } + } + } + + return true; +} + +} // namespace xrpl::protocol_autogen diff --git a/include/xrpl/protocol_autogen/TransactionBase.h b/include/xrpl/protocol_autogen/TransactionBase.h new file mode 100644 index 0000000000..161d718c66 --- /dev/null +++ b/include/xrpl/protocol_autogen/TransactionBase.h @@ -0,0 +1,457 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +/** + * @brief Base class for all transaction wrapper types. + * + * Provides type-safe read-only accessors for common transaction fields. + * This is an immutable wrapper around STTx. Use the corresponding Builder classes + * to construct new transactions. + */ +class TransactionBase +{ +public: + /** + * @brief Construct a transaction wrapper from an existing STTx object. + * @param tx The underlying transaction object to wrap + */ + explicit TransactionBase(std::shared_ptr tx) : tx_(std::move(tx)) + { + } + + /** + * @brief Validate the transaction + * @return true if validation passes, false otherwise + */ + [[nodiscard]] + bool + validate(std::string& reason) const + { + if (!protocol_autogen::validateSTObject( + *tx_, TxFormats::getInstance().findByType(tx_->getTxnType())->getSOTemplate())) + { + // LCOV_EXCL_START + reason = "Transaction failed schema validation"; + return false; + // LCOV_EXCL_STOP + } + + // Pseudo transactions are not submitted to the network + if (isPseudoTx(*tx_)) + { + return true; + } + return passesLocalChecks(*tx_, reason); + } + + /** + * @brief Get the transaction type. + * @return The type of this transaction + */ + [[nodiscard]] + xrpl::TxType + getTransactionType() const + { + return tx_->getTxnType(); + } + + /** + * @brief Get the account initiating the transaction (sfAccount). + * + * This field is REQUIRED for all transactions. + * @return The account ID of the transaction sender + */ + [[nodiscard]] + AccountID + getAccount() const + { + return tx_->at(sfAccount); + } + + /** + * @brief Get the sequence number of the transaction (sfSequence). + * + * This field is REQUIRED for all transactions. + * @return The sequence number + */ + [[nodiscard]] + std::uint32_t + getSequence() const + { + return tx_->at(sfSequence); + } + + /** + * @brief Get the transaction fee (sfFee). + * + * This field is REQUIRED for all transactions. + * @return The fee amount + */ + [[nodiscard]] + STAmount + getFee() const + { + return tx_->at(sfFee); + } + + /** + * @brief Get the signing public key (sfSigningPubKey). + * + * This field is REQUIRED for all transactions. + * @return The public key used for signing as a blob + */ + [[nodiscard]] + Blob + getSigningPubKey() const + { + return tx_->getFieldVL(sfSigningPubKey); + } + + /** + * @brief Get the transaction flags (sfFlags). + * + * This field is OPTIONAL. + * @return The flags value if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getFlags() const + { + if (tx_->isFieldPresent(sfFlags)) + return tx_->at(sfFlags); + return std::nullopt; + } + + /** + * @brief Check if the transaction has flags set. + * @return true if sfFlags is present, false otherwise + */ + [[nodiscard]] + bool + hasFlags() const + { + return tx_->isFieldPresent(sfFlags); + } + + /** + * @brief Get the source tag (sfSourceTag). + * + * This field is OPTIONAL and used to identify the source of a payment. + * @return The source tag value if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getSourceTag() const + { + if (tx_->isFieldPresent(sfSourceTag)) + return tx_->at(sfSourceTag); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a source tag. + * @return true if sfSourceTag is present, false otherwise + */ + [[nodiscard]] + bool + hasSourceTag() const + { + return tx_->isFieldPresent(sfSourceTag); + } + + /** + * @brief Get the previous transaction ID (sfPreviousTxnID). + * + * This field is OPTIONAL and used for transaction chaining. + * @return The previous transaction ID if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getPreviousTxnID() const + { + if (tx_->isFieldPresent(sfPreviousTxnID)) + return tx_->at(sfPreviousTxnID); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a previous transaction ID. + * @return true if sfPreviousTxnID is present, false otherwise + */ + [[nodiscard]] + bool + hasPreviousTxnID() const + { + return tx_->isFieldPresent(sfPreviousTxnID); + } + + /** + * @brief Get the last ledger sequence (sfLastLedgerSequence). + * + * This field is OPTIONAL and specifies the latest ledger sequence + * in which this transaction can be included. + * @return The last ledger sequence if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getLastLedgerSequence() const + { + if (tx_->isFieldPresent(sfLastLedgerSequence)) + return tx_->at(sfLastLedgerSequence); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a last ledger sequence. + * @return true if sfLastLedgerSequence is present, false otherwise + */ + [[nodiscard]] + bool + hasLastLedgerSequence() const + { + return tx_->isFieldPresent(sfLastLedgerSequence); + } + + /** + * @brief Get the account transaction ID (sfAccountTxnID). + * + * This field is OPTIONAL and used to track transaction sequences. + * @return The account transaction ID if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getAccountTxnID() const + { + if (tx_->isFieldPresent(sfAccountTxnID)) + return tx_->at(sfAccountTxnID); + return std::nullopt; + } + + /** + * @brief Check if the transaction has an account transaction ID. + * @return true if sfAccountTxnID is present, false otherwise + */ + [[nodiscard]] + bool + hasAccountTxnID() const + { + return tx_->isFieldPresent(sfAccountTxnID); + } + + /** + * @brief Get the operation limit (sfOperationLimit). + * + * This field is OPTIONAL and limits the number of operations in a transaction. + * @return The operation limit if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getOperationLimit() const + { + if (tx_->isFieldPresent(sfOperationLimit)) + return tx_->at(sfOperationLimit); + return std::nullopt; + } + + /** + * @brief Check if the transaction has an operation limit. + * @return true if sfOperationLimit is present, false otherwise + */ + [[nodiscard]] + bool + hasOperationLimit() const + { + return tx_->isFieldPresent(sfOperationLimit); + } + + /** + * @brief Get the memos array (sfMemos). + * + * This field is OPTIONAL and contains arbitrary data attached to the transaction. + * @note This is an untyped field (STArray). + * @return A reference wrapper to the memos array if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional> + getMemos() const + { + if (tx_->isFieldPresent(sfMemos)) + return tx_->getFieldArray(sfMemos); + return std::nullopt; + } + + /** + * @brief Check if the transaction has memos. + * @return true if sfMemos is present, false otherwise + */ + [[nodiscard]] + bool + hasMemos() const + { + return tx_->isFieldPresent(sfMemos); + } + + /** + * @brief Get the ticket sequence (sfTicketSequence). + * + * This field is OPTIONAL and used when consuming a ticket instead of a sequence number. + * @return The ticket sequence if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getTicketSequence() const + { + if (tx_->isFieldPresent(sfTicketSequence)) + return tx_->at(sfTicketSequence); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a ticket sequence. + * @return true if sfTicketSequence is present, false otherwise + */ + [[nodiscard]] + bool + hasTicketSequence() const + { + return tx_->isFieldPresent(sfTicketSequence); + } + + /** + * @brief Get the transaction signature (sfTxnSignature). + * + * This field is OPTIONAL and contains the signature for single-signed transactions. + * @return The transaction signature as a blob if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getTxnSignature() const + { + if (tx_->isFieldPresent(sfTxnSignature)) + return tx_->getFieldVL(sfTxnSignature); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a transaction signature. + * @return true if sfTxnSignature is present, false otherwise + */ + [[nodiscard]] + bool + hasTxnSignature() const + { + return tx_->isFieldPresent(sfTxnSignature); + } + + /** + * @brief Get the signers array (sfSigners). + * + * This field is OPTIONAL and contains the list of signers for multi-signed transactions. + * @note This is an untyped field (STArray). + * @return A reference wrapper to the signers array if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional> + getSigners() const + { + if (tx_->isFieldPresent(sfSigners)) + return tx_->getFieldArray(sfSigners); + return std::nullopt; + } + + /** + * @brief Check if the transaction has signers. + * @return true if sfSigners is present, false otherwise + */ + [[nodiscard]] + bool + hasSigners() const + { + return tx_->isFieldPresent(sfSigners); + } + + /** + * @brief Get the network ID (sfNetworkID). + * + * This field is OPTIONAL and identifies the network this transaction is intended for. + * @return The network ID if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getNetworkID() const + { + if (tx_->isFieldPresent(sfNetworkID)) + return tx_->at(sfNetworkID); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a network ID. + * @return true if sfNetworkID is present, false otherwise + */ + [[nodiscard]] + bool + hasNetworkID() const + { + return tx_->isFieldPresent(sfNetworkID); + } + + /** + * @brief Get the delegate account (sfDelegate). + * + * This field is OPTIONAL and specifies a delegate account for the transaction. + * @return The delegate account ID if present, std::nullopt otherwise + */ + [[nodiscard]] + std::optional + getDelegate() const + { + if (tx_->isFieldPresent(sfDelegate)) + return tx_->at(sfDelegate); + return std::nullopt; + } + + /** + * @brief Check if the transaction has a delegate account. + * @return true if sfDelegate is present, false otherwise + */ + [[nodiscard]] + bool + hasDelegate() const + { + return tx_->isFieldPresent(sfDelegate); + } + + /** + * @brief Get the underlying STTx object. + * + * Provides direct access to the wrapped transaction object for cases + * where the type-safe accessors are insufficient. + * @return A constant reference to the underlying STTx object + */ + [[nodiscard]] + std::shared_ptr + getSTTx() const + { + return tx_; + } + +protected: + /** @brief The underlying transaction object being wrapped. */ + std::shared_ptr tx_; +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/TransactionBuilderBase.h b/include/xrpl/protocol_autogen/TransactionBuilderBase.h new file mode 100644 index 0000000000..3abfd07a1c --- /dev/null +++ b/include/xrpl/protocol_autogen/TransactionBuilderBase.h @@ -0,0 +1,269 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xrpl::transactions { + +/** + * Base class for all transaction builders. + * Provides common field setters that are available for all transaction types. + */ +template +class TransactionBuilderBase +{ +public: + TransactionBuilderBase() = default; + + TransactionBuilderBase( + SF_UINT16::type::value_type transactionType, + SF_ACCOUNT::type::value_type account, + std::optional sequence, + std::optional fee) + { + // Don't call object_.set(soTemplate) - keep object_ as a free object. + // This avoids creating STBase placeholders for soeDEFAULT fields, + // which would cause applyTemplate() to throw "may not be explicitly + // set to default" when building the STTx. + // The STTx constructor will call applyTemplate() which properly + // handles missing fields. + object_[sfTransactionType] = transactionType; + setAccount(account); + + if (sequence) + { + setSequence(*sequence); + } + if (fee) + { + setFee(*fee); + } + } + + /** + * Set the account that is sending the transaction. + * @param value Account address (typically as a string) + * @return Reference to the derived builder for method chaining. + */ + Derived& + setAccount(AccountID const& value) + { + object_[sfAccount] = value; + return static_cast(*this); + } + + /** + * Set the transaction fee. + * @param value Fee in drops (typically as a string or number) + * @return Reference to the derived builder for method chaining. + */ + Derived& + setFee(STAmount const& value) + { + object_[sfFee] = value; + return static_cast(*this); + } + + /** + * Set the sequence number. + * @param value Sequence number + * @return Reference to the derived builder for method chaining. + */ + Derived& + setSequence(std::uint32_t const& value) + { + object_[sfSequence] = value; + return static_cast(*this); + } + + /** + * Set the ticket sequence to use for this transaction. + * When using a ticket, the regular sequence number is set to 0. + * @param value Ticket sequence number + * @return Reference to the derived builder for method chaining. + */ + Derived& + setTicketSequence(std::uint32_t const& value) + { + object_[sfSequence] = 0u; + object_[sfTicketSequence] = value; + return static_cast(*this); + } + + /** + * Set transaction flags. + * @param value Flags value + * @return Reference to the derived builder for method chaining. + */ + Derived& + setFlags(std::uint32_t const& value) + { + object_[sfFlags] = value; + return static_cast(*this); + } + + /** + * Set the source tag. + * @param value Source tag + * @return Reference to the derived builder for method chaining. + */ + Derived& + setSourceTag(std::uint32_t const& value) + { + object_[sfSourceTag] = value; + return static_cast(*this); + } + + /** + * Set the last ledger sequence. + * @param value Last ledger sequence number + * @return Reference to the derived builder for method chaining. + */ + Derived& + setLastLedgerSequence(std::uint32_t const& value) + { + object_[sfLastLedgerSequence] = value; + return static_cast(*this); + } + + /** + * Set the account transaction ID. + * @param value Account transaction ID (typically as a hex string) + * @return Reference to the derived builder for method chaining. + */ + Derived& + setAccountTxnID(uint256 const& value) + { + object_[sfAccountTxnID] = value; + return static_cast(*this); + } + + /** + * Set the previous transaction ID. + * Used for emulate027 compatibility. + * @param value Previous transaction ID + * @return Reference to the derived builder for method chaining. + */ + Derived& + setPreviousTxnID(uint256 const& value) + { + object_[sfPreviousTxnID] = value; + return static_cast(*this); + } + + /** + * Set the operation limit. + * @param value Operation limit + * @return Reference to the derived builder for method chaining. + */ + Derived& + setOperationLimit(std::uint32_t const& value) + { + object_[sfOperationLimit] = value; + return static_cast(*this); + } + + /** + * Set the memos array. + * @param value Array of memo objects + * @return Reference to the derived builder for method chaining. + */ + Derived& + setMemos(STArray const& value) + { + object_.setFieldArray(sfMemos, value); + return static_cast(*this); + } + + /** + * Set the signers array for multi-signing. + * @param value Array of signer objects + * @return Reference to the derived builder for method chaining. + */ + Derived& + setSigners(STArray const& value) + { + object_.setFieldArray(sfSigners, value); + return static_cast(*this); + } + + /** + * Set the network ID. + * @param value Network ID + * @return Reference to the derived builder for method chaining. + */ + Derived& + setNetworkID(std::uint32_t const& value) + { + object_[sfNetworkID] = value; + return static_cast(*this); + } + + /** + * Set the delegate account for delegated transactions. + * @param value Delegate account ID + * @return Reference to the derived builder for method chaining. + */ + Derived& + setDelegate(AccountID const& value) + { + object_[sfDelegate] = value; + return static_cast(*this); + } + + /** + * Get the underlying STObject. + * @return The STObject + */ + STObject const& + getSTObject() const + { + return object_; + } + +protected: + /** + * Sign the transaction with the given keys. + * + * This sets the SigningPubKey field and computes the TxnSignature. + * + * @param publicKey The public key for signing + * @param secretKey The secret key for signing + * @return Reference to the derived builder for method chaining. + */ + Derived& + sign(PublicKey const& publicKey, SecretKey const& secretKey) + { + // Set the signing public key + object_.setFieldVL(sfSigningPubKey, publicKey.slice()); + + // Build the signing data: HashPrefix::txSign + serialized object + // (without signing fields) + Serializer s; + s.add32(HashPrefix::txSign); + object_.addWithoutSigningFields(s); + + // Sign and set the signature + auto const sig = xrpl::sign(publicKey, secretKey, s.slice()); + object_.setFieldVL(sfTxnSignature, sig); + + return static_cast(*this); + } + + STObject object_{sfTransaction}; +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/Utils.h b/include/xrpl/protocol_autogen/Utils.h new file mode 100644 index 0000000000..057c685209 --- /dev/null +++ b/include/xrpl/protocol_autogen/Utils.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace xrpl::protocol_autogen { + +template +using Optional = std::conditional_t< + std::is_reference_v, + std::optional>>, + std::optional>; + +} diff --git a/include/xrpl/protocol_autogen/ledger_entries/AMM.h b/include/xrpl/protocol_autogen/ledger_entries/AMM.h new file mode 100644 index 0000000000..f92f15eaa8 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/AMM.h @@ -0,0 +1,392 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class AMMBuilder; + +/** + * @brief Ledger Entry: AMM + * + * Type: ltAMM (0x0079) + * RPC Name: amm + * + * Immutable wrapper around SLE providing type-safe field access. + * Use AMMBuilder to construct new ledger entries. + */ +class AMM : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltAMM; + + /** + * @brief Construct a AMM ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit AMM(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for AMM"); + } + } + + // 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 sfTradingFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTradingFee() const + { + if (hasTradingFee()) + return this->sle_->at(sfTradingFee); + return std::nullopt; + } + + /** + * @brief Check if sfTradingFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTradingFee() const + { + return this->sle_->isFieldPresent(sfTradingFee); + } + + /** + * @brief Get sfVoteSlots (soeOPTIONAL) + * @note This is an untyped field (unknown). + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getVoteSlots() const + { + if (this->sle_->isFieldPresent(sfVoteSlots)) + return this->sle_->getFieldArray(sfVoteSlots); + return std::nullopt; + } + + /** + * @brief Check if sfVoteSlots is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasVoteSlots() const + { + return this->sle_->isFieldPresent(sfVoteSlots); + } + + /** + * @brief Get sfAuctionSlot (soeOPTIONAL) + * @note This is an untyped field (unknown). + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional + getAuctionSlot() const + { + if (this->sle_->isFieldPresent(sfAuctionSlot)) + return this->sle_->getFieldObject(sfAuctionSlot); + return std::nullopt; + } + + /** + * @brief Check if sfAuctionSlot is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAuctionSlot() const + { + return this->sle_->isFieldPresent(sfAuctionSlot); + } + + /** + * @brief Get sfLPTokenBalance (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getLPTokenBalance() const + { + return this->sle_->at(sfLPTokenBalance); + } + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->sle_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->sle_->at(sfAsset2); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfPreviousTxnID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnID() const + { + if (hasPreviousTxnID()) + return this->sle_->at(sfPreviousTxnID); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnID() const + { + return this->sle_->isFieldPresent(sfPreviousTxnID); + } + + /** + * @brief Get sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnLgrSeq() const + { + if (hasPreviousTxnLgrSeq()) + return this->sle_->at(sfPreviousTxnLgrSeq); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnLgrSeq is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnLgrSeq() const + { + return this->sle_->isFieldPresent(sfPreviousTxnLgrSeq); + } +}; + +/** + * @brief Builder for AMM ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class AMMBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new AMMBuilder with required fields. + * @param account The sfAccount field value. + * @param lPTokenBalance The sfLPTokenBalance field value. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param ownerNode The sfOwnerNode field value. + */ + AMMBuilder(std::decay_t const& account,std::decay_t const& lPTokenBalance,std::decay_t const& asset,std::decay_t const& asset2,std::decay_t const& ownerNode) + : LedgerEntryBuilderBase(ltAMM) + { + setAccount(account); + setLPTokenBalance(lPTokenBalance); + setAsset(asset); + setAsset2(asset2); + setOwnerNode(ownerNode); + } + + /** + * @brief Construct a AMMBuilder 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. + */ + AMMBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltAMM) + { + throw std::runtime_error("Invalid ledger entry type for AMM"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfTradingFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setTradingFee(std::decay_t const& value) + { + object_[sfTradingFee] = value; + return *this; + } + + /** + * @brief Set sfVoteSlots (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setVoteSlots(STArray const& value) + { + object_.setFieldArray(sfVoteSlots, value); + return *this; + } + + /** + * @brief Set sfAuctionSlot (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setAuctionSlot(STObject const& value) + { + object_.setFieldObject(sfAuctionSlot, value); + return *this; + } + + /** + * @brief Set sfLPTokenBalance (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setLPTokenBalance(std::decay_t const& value) + { + object_[sfLPTokenBalance] = value; + return *this; + } + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed AMM wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + AMM + build(uint256 const& index) + { + return AMM{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/AccountRoot.h b/include/xrpl/protocol_autogen/ledger_entries/AccountRoot.h new file mode 100644 index 0000000000..15cf14b21a --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/AccountRoot.h @@ -0,0 +1,834 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class AccountRootBuilder; + +/** + * @brief Ledger Entry: AccountRoot + * + * Type: ltACCOUNT_ROOT (0x0061) + * RPC Name: account + * + * Immutable wrapper around SLE providing type-safe field access. + * Use AccountRootBuilder to construct new ledger entries. + */ +class AccountRoot : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltACCOUNT_ROOT; + + /** + * @brief Construct a AccountRoot ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit AccountRoot(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for AccountRoot"); + } + } + + // 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 sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfBalance (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getBalance() const + { + return this->sle_->at(sfBalance); + } + + /** + * @brief Get sfOwnerCount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getOwnerCount() const + { + return this->sle_->at(sfOwnerCount); + } + + /** + * @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 sfAccountTxnID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAccountTxnID() const + { + if (hasAccountTxnID()) + return this->sle_->at(sfAccountTxnID); + return std::nullopt; + } + + /** + * @brief Check if sfAccountTxnID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAccountTxnID() const + { + return this->sle_->isFieldPresent(sfAccountTxnID); + } + + /** + * @brief Get sfRegularKey (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getRegularKey() const + { + if (hasRegularKey()) + return this->sle_->at(sfRegularKey); + return std::nullopt; + } + + /** + * @brief Check if sfRegularKey is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasRegularKey() const + { + return this->sle_->isFieldPresent(sfRegularKey); + } + + /** + * @brief Get sfEmailHash (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getEmailHash() const + { + if (hasEmailHash()) + return this->sle_->at(sfEmailHash); + return std::nullopt; + } + + /** + * @brief Check if sfEmailHash is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasEmailHash() const + { + return this->sle_->isFieldPresent(sfEmailHash); + } + + /** + * @brief Get sfWalletLocator (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getWalletLocator() const + { + if (hasWalletLocator()) + return this->sle_->at(sfWalletLocator); + return std::nullopt; + } + + /** + * @brief Check if sfWalletLocator is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasWalletLocator() const + { + return this->sle_->isFieldPresent(sfWalletLocator); + } + + /** + * @brief Get sfWalletSize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getWalletSize() const + { + if (hasWalletSize()) + return this->sle_->at(sfWalletSize); + return std::nullopt; + } + + /** + * @brief Check if sfWalletSize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasWalletSize() const + { + return this->sle_->isFieldPresent(sfWalletSize); + } + + /** + * @brief Get sfMessageKey (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMessageKey() const + { + if (hasMessageKey()) + return this->sle_->at(sfMessageKey); + return std::nullopt; + } + + /** + * @brief Check if sfMessageKey is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMessageKey() const + { + return this->sle_->isFieldPresent(sfMessageKey); + } + + /** + * @brief Get sfTransferRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferRate() const + { + if (hasTransferRate()) + return this->sle_->at(sfTransferRate); + return std::nullopt; + } + + /** + * @brief Check if sfTransferRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferRate() const + { + return this->sle_->isFieldPresent(sfTransferRate); + } + + /** + * @brief Get sfDomain (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomain() const + { + if (hasDomain()) + return this->sle_->at(sfDomain); + return std::nullopt; + } + + /** + * @brief Check if sfDomain is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomain() const + { + return this->sle_->isFieldPresent(sfDomain); + } + + /** + * @brief Get sfTickSize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTickSize() const + { + if (hasTickSize()) + return this->sle_->at(sfTickSize); + return std::nullopt; + } + + /** + * @brief Check if sfTickSize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTickSize() const + { + return this->sle_->isFieldPresent(sfTickSize); + } + + /** + * @brief Get sfTicketCount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTicketCount() const + { + if (hasTicketCount()) + return this->sle_->at(sfTicketCount); + return std::nullopt; + } + + /** + * @brief Check if sfTicketCount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTicketCount() const + { + return this->sle_->isFieldPresent(sfTicketCount); + } + + /** + * @brief Get sfNFTokenMinter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNFTokenMinter() const + { + if (hasNFTokenMinter()) + return this->sle_->at(sfNFTokenMinter); + return std::nullopt; + } + + /** + * @brief Check if sfNFTokenMinter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNFTokenMinter() const + { + return this->sle_->isFieldPresent(sfNFTokenMinter); + } + + /** + * @brief Get sfMintedNFTokens (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMintedNFTokens() const + { + if (hasMintedNFTokens()) + return this->sle_->at(sfMintedNFTokens); + return std::nullopt; + } + + /** + * @brief Check if sfMintedNFTokens is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMintedNFTokens() const + { + return this->sle_->isFieldPresent(sfMintedNFTokens); + } + + /** + * @brief Get sfBurnedNFTokens (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBurnedNFTokens() const + { + if (hasBurnedNFTokens()) + return this->sle_->at(sfBurnedNFTokens); + return std::nullopt; + } + + /** + * @brief Check if sfBurnedNFTokens is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBurnedNFTokens() const + { + return this->sle_->isFieldPresent(sfBurnedNFTokens); + } + + /** + * @brief Get sfFirstNFTokenSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getFirstNFTokenSequence() const + { + if (hasFirstNFTokenSequence()) + return this->sle_->at(sfFirstNFTokenSequence); + return std::nullopt; + } + + /** + * @brief Check if sfFirstNFTokenSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasFirstNFTokenSequence() const + { + return this->sle_->isFieldPresent(sfFirstNFTokenSequence); + } + + /** + * @brief Get sfAMMID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAMMID() const + { + if (hasAMMID()) + return this->sle_->at(sfAMMID); + return std::nullopt; + } + + /** + * @brief Check if sfAMMID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAMMID() const + { + return this->sle_->isFieldPresent(sfAMMID); + } + + /** + * @brief Get sfVaultID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getVaultID() const + { + if (hasVaultID()) + return this->sle_->at(sfVaultID); + return std::nullopt; + } + + /** + * @brief Check if sfVaultID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasVaultID() const + { + return this->sle_->isFieldPresent(sfVaultID); + } + + /** + * @brief Get sfLoanBrokerID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanBrokerID() const + { + if (hasLoanBrokerID()) + return this->sle_->at(sfLoanBrokerID); + return std::nullopt; + } + + /** + * @brief Check if sfLoanBrokerID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanBrokerID() const + { + return this->sle_->isFieldPresent(sfLoanBrokerID); + } +}; + +/** + * @brief Builder for AccountRoot ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class AccountRootBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new AccountRootBuilder with required fields. + * @param account The sfAccount field value. + * @param sequence The sfSequence field value. + * @param balance The sfBalance field value. + * @param ownerCount The sfOwnerCount field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + AccountRootBuilder(std::decay_t const& account,std::decay_t const& sequence,std::decay_t const& balance,std::decay_t const& ownerCount,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltACCOUNT_ROOT) + { + setAccount(account); + setSequence(sequence); + setBalance(balance); + setOwnerCount(ownerCount); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a AccountRootBuilder 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. + */ + AccountRootBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltACCOUNT_ROOT) + { + throw std::runtime_error("Invalid ledger entry type for AccountRoot"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfBalance (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setBalance(std::decay_t const& value) + { + object_[sfBalance] = value; + return *this; + } + + /** + * @brief Set sfOwnerCount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setOwnerCount(std::decay_t const& value) + { + object_[sfOwnerCount] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfAccountTxnID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setAccountTxnID(std::decay_t const& value) + { + object_[sfAccountTxnID] = value; + return *this; + } + + /** + * @brief Set sfRegularKey (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setRegularKey(std::decay_t const& value) + { + object_[sfRegularKey] = value; + return *this; + } + + /** + * @brief Set sfEmailHash (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setEmailHash(std::decay_t const& value) + { + object_[sfEmailHash] = value; + return *this; + } + + /** + * @brief Set sfWalletLocator (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setWalletLocator(std::decay_t const& value) + { + object_[sfWalletLocator] = value; + return *this; + } + + /** + * @brief Set sfWalletSize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setWalletSize(std::decay_t const& value) + { + object_[sfWalletSize] = value; + return *this; + } + + /** + * @brief Set sfMessageKey (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setMessageKey(std::decay_t const& value) + { + object_[sfMessageKey] = value; + return *this; + } + + /** + * @brief Set sfTransferRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setTransferRate(std::decay_t const& value) + { + object_[sfTransferRate] = value; + return *this; + } + + /** + * @brief Set sfDomain (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setDomain(std::decay_t const& value) + { + object_[sfDomain] = value; + return *this; + } + + /** + * @brief Set sfTickSize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setTickSize(std::decay_t const& value) + { + object_[sfTickSize] = value; + return *this; + } + + /** + * @brief Set sfTicketCount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setTicketCount(std::decay_t const& value) + { + object_[sfTicketCount] = value; + return *this; + } + + /** + * @brief Set sfNFTokenMinter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setNFTokenMinter(std::decay_t const& value) + { + object_[sfNFTokenMinter] = value; + return *this; + } + + /** + * @brief Set sfMintedNFTokens (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setMintedNFTokens(std::decay_t const& value) + { + object_[sfMintedNFTokens] = value; + return *this; + } + + /** + * @brief Set sfBurnedNFTokens (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setBurnedNFTokens(std::decay_t const& value) + { + object_[sfBurnedNFTokens] = value; + return *this; + } + + /** + * @brief Set sfFirstNFTokenSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setFirstNFTokenSequence(std::decay_t const& value) + { + object_[sfFirstNFTokenSequence] = value; + return *this; + } + + /** + * @brief Set sfAMMID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setAMMID(std::decay_t const& value) + { + object_[sfAMMID] = value; + return *this; + } + + /** + * @brief Set sfVaultID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfLoanBrokerID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountRootBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Build and return the completed AccountRoot wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + AccountRoot + build(uint256 const& index) + { + return AccountRoot{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Amendments.h b/include/xrpl/protocol_autogen/ledger_entries/Amendments.h new file mode 100644 index 0000000000..2b51b83747 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Amendments.h @@ -0,0 +1,236 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class AmendmentsBuilder; + +/** + * @brief Ledger Entry: Amendments + * + * Type: ltAMENDMENTS (0x0066) + * RPC Name: amendments + * + * Immutable wrapper around SLE providing type-safe field access. + * Use AmendmentsBuilder to construct new ledger entries. + */ +class Amendments : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltAMENDMENTS; + + /** + * @brief Construct a Amendments ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Amendments(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Amendments"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfAmendments (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmendments() const + { + if (hasAmendments()) + return this->sle_->at(sfAmendments); + return std::nullopt; + } + + /** + * @brief Check if sfAmendments is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmendments() const + { + return this->sle_->isFieldPresent(sfAmendments); + } + + /** + * @brief Get sfMajorities (soeOPTIONAL) + * @note This is an untyped field (unknown). + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getMajorities() const + { + if (this->sle_->isFieldPresent(sfMajorities)) + return this->sle_->getFieldArray(sfMajorities); + return std::nullopt; + } + + /** + * @brief Check if sfMajorities is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMajorities() const + { + return this->sle_->isFieldPresent(sfMajorities); + } + + /** + * @brief Get sfPreviousTxnID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnID() const + { + if (hasPreviousTxnID()) + return this->sle_->at(sfPreviousTxnID); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnID() const + { + return this->sle_->isFieldPresent(sfPreviousTxnID); + } + + /** + * @brief Get sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnLgrSeq() const + { + if (hasPreviousTxnLgrSeq()) + return this->sle_->at(sfPreviousTxnLgrSeq); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnLgrSeq is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnLgrSeq() const + { + return this->sle_->isFieldPresent(sfPreviousTxnLgrSeq); + } +}; + +/** + * @brief Builder for Amendments ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class AmendmentsBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new AmendmentsBuilder with required fields. + */ + AmendmentsBuilder() + : LedgerEntryBuilderBase(ltAMENDMENTS) + { + } + + /** + * @brief Construct a AmendmentsBuilder 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. + */ + AmendmentsBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltAMENDMENTS) + { + throw std::runtime_error("Invalid ledger entry type for Amendments"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAmendments (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AmendmentsBuilder& + setAmendments(std::decay_t const& value) + { + object_[sfAmendments] = value; + return *this; + } + + /** + * @brief Set sfMajorities (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AmendmentsBuilder& + setMajorities(STArray const& value) + { + object_.setFieldArray(sfMajorities, value); + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AmendmentsBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AmendmentsBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed Amendments wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Amendments + build(uint256 const& index) + { + return Amendments{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Bridge.h b/include/xrpl/protocol_autogen/ledger_entries/Bridge.h new file mode 100644 index 0000000000..3926ff65fa --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Bridge.h @@ -0,0 +1,346 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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(std::shared_ptr 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 + 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 Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class BridgeBuilder : public LedgerEntryBuilderBase +{ +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 const& account,std::decay_t const& signatureReward,std::decay_t const& xChainBridge,std::decay_t const& xChainClaimID,std::decay_t const& xChainAccountCreateCount,std::decay_t const& xChainAccountClaimCount,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(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(std::shared_ptr 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 const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfSignatureReward (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setSignatureReward(std::decay_t const& value) + { + object_[sfSignatureReward] = value; + return *this; + } + + /** + * @brief Set sfMinAccountCreateAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setMinAccountCreateAmount(std::decay_t const& value) + { + object_[sfMinAccountCreateAmount] = value; + return *this; + } + + /** + * @brief Set sfXChainBridge (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setXChainBridge(std::decay_t const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfXChainClaimID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setXChainClaimID(std::decay_t const& value) + { + object_[sfXChainClaimID] = value; + return *this; + } + + /** + * @brief Set sfXChainAccountCreateCount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setXChainAccountCreateCount(std::decay_t const& value) + { + object_[sfXChainAccountCreateCount] = value; + return *this; + } + + /** + * @brief Set sfXChainAccountClaimCount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setXChainAccountClaimCount(std::decay_t const& value) + { + object_[sfXChainAccountClaimCount] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BridgeBuilder& + setPreviousTxnLgrSeq(std::decay_t 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(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Check.h b/include/xrpl/protocol_autogen/ledger_entries/Check.h new file mode 100644 index 0000000000..c071186afb --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Check.h @@ -0,0 +1,427 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class CheckBuilder; + +/** + * @brief Ledger Entry: Check + * + * Type: ltCHECK (0x0043) + * RPC Name: check + * + * Immutable wrapper around SLE providing type-safe field access. + * Use CheckBuilder to construct new ledger entries. + */ +class Check : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltCHECK; + + /** + * @brief Construct a Check ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Check(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Check"); + } + } + + // 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 sfDestination (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getDestination() const + { + return this->sle_->at(sfDestination); + } + + /** + * @brief Get sfSendMax (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getSendMax() const + { + return this->sle_->at(sfSendMax); + } + + /** + * @brief Get sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfDestinationNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getDestinationNode() const + { + return this->sle_->at(sfDestinationNode); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + return this->sle_->at(sfExpiration); + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->sle_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfInvoiceID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getInvoiceID() const + { + if (hasInvoiceID()) + return this->sle_->at(sfInvoiceID); + return std::nullopt; + } + + /** + * @brief Check if sfInvoiceID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasInvoiceID() const + { + return this->sle_->isFieldPresent(sfInvoiceID); + } + + /** + * @brief Get sfSourceTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSourceTag() const + { + if (hasSourceTag()) + return this->sle_->at(sfSourceTag); + return std::nullopt; + } + + /** + * @brief Check if sfSourceTag is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSourceTag() const + { + return this->sle_->isFieldPresent(sfSourceTag); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDestinationTag() const + { + if (hasDestinationTag()) + return this->sle_->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->sle_->isFieldPresent(sfDestinationTag); + } + + /** + * @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 Check ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class CheckBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new CheckBuilder with required fields. + * @param account The sfAccount field value. + * @param destination The sfDestination field value. + * @param sendMax The sfSendMax field value. + * @param sequence The sfSequence field value. + * @param ownerNode The sfOwnerNode field value. + * @param destinationNode The sfDestinationNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + CheckBuilder(std::decay_t const& account,std::decay_t const& destination,std::decay_t const& sendMax,std::decay_t const& sequence,std::decay_t const& ownerNode,std::decay_t const& destinationNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltCHECK) + { + setAccount(account); + setDestination(destination); + setSendMax(sendMax); + setSequence(sequence); + setOwnerNode(ownerNode); + setDestinationNode(destinationNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a CheckBuilder 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. + */ + CheckBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltCHECK) + { + throw std::runtime_error("Invalid ledger entry type for Check"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfSendMax (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setSendMax(std::decay_t const& value) + { + object_[sfSendMax] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfDestinationNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setDestinationNode(std::decay_t const& value) + { + object_[sfDestinationNode] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfInvoiceID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setInvoiceID(std::decay_t const& value) + { + object_[sfInvoiceID] = value; + return *this; + } + + /** + * @brief Set sfSourceTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setSourceTag(std::decay_t const& value) + { + object_[sfSourceTag] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed Check wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Check + build(uint256 const& index) + { + return Check{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Credential.h b/include/xrpl/protocol_autogen/ledger_entries/Credential.h new file mode 100644 index 0000000000..4c45f80a8d --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Credential.h @@ -0,0 +1,344 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class CredentialBuilder; + +/** + * @brief Ledger Entry: Credential + * + * Type: ltCREDENTIAL (0x0081) + * RPC Name: credential + * + * Immutable wrapper around SLE providing type-safe field access. + * Use CredentialBuilder to construct new ledger entries. + */ +class Credential : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltCREDENTIAL; + + /** + * @brief Construct a Credential ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Credential(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Credential"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfSubject (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getSubject() const + { + return this->sle_->at(sfSubject); + } + + /** + * @brief Get sfIssuer (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getIssuer() const + { + return this->sle_->at(sfIssuer); + } + + /** + * @brief Get sfCredentialType (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getCredentialType() const + { + return this->sle_->at(sfCredentialType); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + return this->sle_->at(sfExpiration); + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->sle_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + return this->sle_->at(sfURI); + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->sle_->isFieldPresent(sfURI); + } + + /** + * @brief Get sfIssuerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getIssuerNode() const + { + return this->sle_->at(sfIssuerNode); + } + + /** + * @brief Get sfSubjectNode (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSubjectNode() const + { + if (hasSubjectNode()) + return this->sle_->at(sfSubjectNode); + return std::nullopt; + } + + /** + * @brief Check if sfSubjectNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSubjectNode() const + { + return this->sle_->isFieldPresent(sfSubjectNode); + } + + /** + * @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 Credential ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class CredentialBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new CredentialBuilder with required fields. + * @param subject The sfSubject field value. + * @param issuer The sfIssuer field value. + * @param credentialType The sfCredentialType field value. + * @param issuerNode The sfIssuerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + CredentialBuilder(std::decay_t const& subject,std::decay_t const& issuer,std::decay_t const& credentialType,std::decay_t const& issuerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltCREDENTIAL) + { + setSubject(subject); + setIssuer(issuer); + setCredentialType(credentialType); + setIssuerNode(issuerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a CredentialBuilder 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. + */ + CredentialBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltCREDENTIAL) + { + throw std::runtime_error("Invalid ledger entry type for Credential"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfSubject (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setSubject(std::decay_t const& value) + { + object_[sfSubject] = value; + return *this; + } + + /** + * @brief Set sfIssuer (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setIssuer(std::decay_t const& value) + { + object_[sfIssuer] = value; + return *this; + } + + /** + * @brief Set sfCredentialType (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setCredentialType(std::decay_t const& value) + { + object_[sfCredentialType] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Set sfIssuerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setIssuerNode(std::decay_t const& value) + { + object_[sfIssuerNode] = value; + return *this; + } + + /** + * @brief Set sfSubjectNode (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setSubjectNode(std::decay_t const& value) + { + object_[sfSubjectNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed Credential wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Credential + build(uint256 const& index) + { + return Credential{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/DID.h b/include/xrpl/protocol_autogen/ledger_entries/DID.h new file mode 100644 index 0000000000..fc88e988df --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/DID.h @@ -0,0 +1,296 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class DIDBuilder; + +/** + * @brief Ledger Entry: DID + * + * Type: ltDID (0x0049) + * RPC Name: did + * + * Immutable wrapper around SLE providing type-safe field access. + * Use DIDBuilder to construct new ledger entries. + */ +class DID : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltDID; + + /** + * @brief Construct a DID ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit DID(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for DID"); + } + } + + // 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 sfDIDDocument (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDIDDocument() const + { + if (hasDIDDocument()) + return this->sle_->at(sfDIDDocument); + return std::nullopt; + } + + /** + * @brief Check if sfDIDDocument is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDIDDocument() const + { + return this->sle_->isFieldPresent(sfDIDDocument); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + return this->sle_->at(sfURI); + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->sle_->isFieldPresent(sfURI); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + return this->sle_->at(sfData); + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->sle_->isFieldPresent(sfData); + } + + /** + * @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 DID ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class DIDBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new DIDBuilder with required fields. + * @param account The sfAccount field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + DIDBuilder(std::decay_t const& account,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltDID) + { + setAccount(account); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a DIDBuilder 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. + */ + DIDBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltDID) + { + throw std::runtime_error("Invalid ledger entry type for DID"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfDIDDocument (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setDIDDocument(std::decay_t const& value) + { + object_[sfDIDDocument] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DIDBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed DID wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + DID + build(uint256 const& index) + { + return DID{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Delegate.h b/include/xrpl/protocol_autogen/ledger_entries/Delegate.h new file mode 100644 index 0000000000..4d937eb99a --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Delegate.h @@ -0,0 +1,240 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class DelegateBuilder; + +/** + * @brief Ledger Entry: Delegate + * + * Type: ltDELEGATE (0x0083) + * RPC Name: delegate + * + * Immutable wrapper around SLE providing type-safe field access. + * Use DelegateBuilder to construct new ledger entries. + */ +class Delegate : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltDELEGATE; + + /** + * @brief Construct a Delegate ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Delegate(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Delegate"); + } + } + + // 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 sfAuthorize (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getAuthorize() const + { + return this->sle_->at(sfAuthorize); + } + + /** + * @brief Get sfPermissions (soeREQUIRED) + * @note This is an untyped field (unknown). + * @return The field value. + */ + [[nodiscard]] + STArray const& + getPermissions() const + { + return this->sle_->getFieldArray(sfPermissions); + } + + /** + * @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 Delegate ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class DelegateBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new DelegateBuilder with required fields. + * @param account The sfAccount field value. + * @param authorize The sfAuthorize field value. + * @param permissions The sfPermissions field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + DelegateBuilder(std::decay_t const& account,std::decay_t const& authorize,STArray const& permissions,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltDELEGATE) + { + setAccount(account); + setAuthorize(authorize); + setPermissions(permissions); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a DelegateBuilder 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. + */ + DelegateBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltDELEGATE) + { + throw std::runtime_error("Invalid ledger entry type for Delegate"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfAuthorize (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateBuilder& + setAuthorize(std::decay_t const& value) + { + object_[sfAuthorize] = value; + return *this; + } + + /** + * @brief Set sfPermissions (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateBuilder& + setPermissions(STArray const& value) + { + object_.setFieldArray(sfPermissions, value); + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed Delegate wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Delegate + build(uint256 const& index) + { + return Delegate{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/DepositPreauth.h b/include/xrpl/protocol_autogen/ledger_entries/DepositPreauth.h new file mode 100644 index 0000000000..533caba619 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/DepositPreauth.h @@ -0,0 +1,262 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class DepositPreauthBuilder; + +/** + * @brief Ledger Entry: DepositPreauth + * + * Type: ltDEPOSIT_PREAUTH (0x0070) + * RPC Name: deposit_preauth + * + * Immutable wrapper around SLE providing type-safe field access. + * Use DepositPreauthBuilder to construct new ledger entries. + */ +class DepositPreauth : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltDEPOSIT_PREAUTH; + + /** + * @brief Construct a DepositPreauth ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit DepositPreauth(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for DepositPreauth"); + } + } + + // 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 sfAuthorize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAuthorize() const + { + if (hasAuthorize()) + return this->sle_->at(sfAuthorize); + return std::nullopt; + } + + /** + * @brief Check if sfAuthorize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAuthorize() const + { + return this->sle_->isFieldPresent(sfAuthorize); + } + + /** + * @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 Get sfAuthorizeCredentials (soeOPTIONAL) + * @note This is an untyped field (unknown). + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getAuthorizeCredentials() const + { + if (this->sle_->isFieldPresent(sfAuthorizeCredentials)) + return this->sle_->getFieldArray(sfAuthorizeCredentials); + return std::nullopt; + } + + /** + * @brief Check if sfAuthorizeCredentials is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAuthorizeCredentials() const + { + return this->sle_->isFieldPresent(sfAuthorizeCredentials); + } +}; + +/** + * @brief Builder for DepositPreauth ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class DepositPreauthBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new DepositPreauthBuilder with required fields. + * @param account The sfAccount field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + DepositPreauthBuilder(std::decay_t const& account,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltDEPOSIT_PREAUTH) + { + setAccount(account); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a DepositPreauthBuilder 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. + */ + DepositPreauthBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltDEPOSIT_PREAUTH) + { + throw std::runtime_error("Invalid ledger entry type for DepositPreauth"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfAuthorize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setAuthorize(std::decay_t const& value) + { + object_[sfAuthorize] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfAuthorizeCredentials (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setAuthorizeCredentials(STArray const& value) + { + object_.setFieldArray(sfAuthorizeCredentials, value); + return *this; + } + + /** + * @brief Build and return the completed DepositPreauth wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + DepositPreauth + build(uint256 const& index) + { + return DepositPreauth{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/DirectoryNode.h b/include/xrpl/protocol_autogen/ledger_entries/DirectoryNode.h new file mode 100644 index 0000000000..545542ec6c --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/DirectoryNode.h @@ -0,0 +1,563 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class DirectoryNodeBuilder; + +/** + * @brief Ledger Entry: DirectoryNode + * + * Type: ltDIR_NODE (0x0064) + * RPC Name: directory + * + * Immutable wrapper around SLE providing type-safe field access. + * Use DirectoryNodeBuilder to construct new ledger entries. + */ +class DirectoryNode : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltDIR_NODE; + + /** + * @brief Construct a DirectoryNode ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit DirectoryNode(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for DirectoryNode"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfOwner (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwner() const + { + if (hasOwner()) + return this->sle_->at(sfOwner); + return std::nullopt; + } + + /** + * @brief Check if sfOwner is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwner() const + { + return this->sle_->isFieldPresent(sfOwner); + } + + /** + * @brief Get sfTakerPaysCurrency (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTakerPaysCurrency() const + { + if (hasTakerPaysCurrency()) + return this->sle_->at(sfTakerPaysCurrency); + return std::nullopt; + } + + /** + * @brief Check if sfTakerPaysCurrency is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTakerPaysCurrency() const + { + return this->sle_->isFieldPresent(sfTakerPaysCurrency); + } + + /** + * @brief Get sfTakerPaysIssuer (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTakerPaysIssuer() const + { + if (hasTakerPaysIssuer()) + return this->sle_->at(sfTakerPaysIssuer); + return std::nullopt; + } + + /** + * @brief Check if sfTakerPaysIssuer is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTakerPaysIssuer() const + { + return this->sle_->isFieldPresent(sfTakerPaysIssuer); + } + + /** + * @brief Get sfTakerGetsCurrency (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTakerGetsCurrency() const + { + if (hasTakerGetsCurrency()) + return this->sle_->at(sfTakerGetsCurrency); + return std::nullopt; + } + + /** + * @brief Check if sfTakerGetsCurrency is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTakerGetsCurrency() const + { + return this->sle_->isFieldPresent(sfTakerGetsCurrency); + } + + /** + * @brief Get sfTakerGetsIssuer (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTakerGetsIssuer() const + { + if (hasTakerGetsIssuer()) + return this->sle_->at(sfTakerGetsIssuer); + return std::nullopt; + } + + /** + * @brief Check if sfTakerGetsIssuer is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTakerGetsIssuer() const + { + return this->sle_->isFieldPresent(sfTakerGetsIssuer); + } + + /** + * @brief Get sfExchangeRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExchangeRate() const + { + if (hasExchangeRate()) + return this->sle_->at(sfExchangeRate); + return std::nullopt; + } + + /** + * @brief Check if sfExchangeRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExchangeRate() const + { + return this->sle_->isFieldPresent(sfExchangeRate); + } + + /** + * @brief Get sfIndexes (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VECTOR256::type::value_type + getIndexes() const + { + return this->sle_->at(sfIndexes); + } + + /** + * @brief Get sfRootIndex (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getRootIndex() const + { + return this->sle_->at(sfRootIndex); + } + + /** + * @brief Get sfIndexNext (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getIndexNext() const + { + if (hasIndexNext()) + return this->sle_->at(sfIndexNext); + return std::nullopt; + } + + /** + * @brief Check if sfIndexNext is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasIndexNext() const + { + return this->sle_->isFieldPresent(sfIndexNext); + } + + /** + * @brief Get sfIndexPrevious (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getIndexPrevious() const + { + if (hasIndexPrevious()) + return this->sle_->at(sfIndexPrevious); + return std::nullopt; + } + + /** + * @brief Check if sfIndexPrevious is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasIndexPrevious() const + { + return this->sle_->isFieldPresent(sfIndexPrevious); + } + + /** + * @brief Get sfNFTokenID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNFTokenID() const + { + if (hasNFTokenID()) + return this->sle_->at(sfNFTokenID); + return std::nullopt; + } + + /** + * @brief Check if sfNFTokenID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNFTokenID() const + { + return this->sle_->isFieldPresent(sfNFTokenID); + } + + /** + * @brief Get sfPreviousTxnID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnID() const + { + if (hasPreviousTxnID()) + return this->sle_->at(sfPreviousTxnID); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnID() const + { + return this->sle_->isFieldPresent(sfPreviousTxnID); + } + + /** + * @brief Get sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnLgrSeq() const + { + if (hasPreviousTxnLgrSeq()) + return this->sle_->at(sfPreviousTxnLgrSeq); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnLgrSeq is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnLgrSeq() const + { + return this->sle_->isFieldPresent(sfPreviousTxnLgrSeq); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + return this->sle_->at(sfDomainID); + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->sle_->isFieldPresent(sfDomainID); + } +}; + +/** + * @brief Builder for DirectoryNode ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class DirectoryNodeBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new DirectoryNodeBuilder with required fields. + * @param indexes The sfIndexes field value. + * @param rootIndex The sfRootIndex field value. + */ + DirectoryNodeBuilder(std::decay_t const& indexes,std::decay_t const& rootIndex) + : LedgerEntryBuilderBase(ltDIR_NODE) + { + setIndexes(indexes); + setRootIndex(rootIndex); + } + + /** + * @brief Construct a DirectoryNodeBuilder 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. + */ + DirectoryNodeBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltDIR_NODE) + { + throw std::runtime_error("Invalid ledger entry type for DirectoryNode"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfOwner (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfTakerPaysCurrency (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setTakerPaysCurrency(std::decay_t const& value) + { + object_[sfTakerPaysCurrency] = value; + return *this; + } + + /** + * @brief Set sfTakerPaysIssuer (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setTakerPaysIssuer(std::decay_t const& value) + { + object_[sfTakerPaysIssuer] = value; + return *this; + } + + /** + * @brief Set sfTakerGetsCurrency (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setTakerGetsCurrency(std::decay_t const& value) + { + object_[sfTakerGetsCurrency] = value; + return *this; + } + + /** + * @brief Set sfTakerGetsIssuer (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setTakerGetsIssuer(std::decay_t const& value) + { + object_[sfTakerGetsIssuer] = value; + return *this; + } + + /** + * @brief Set sfExchangeRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setExchangeRate(std::decay_t const& value) + { + object_[sfExchangeRate] = value; + return *this; + } + + /** + * @brief Set sfIndexes (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setIndexes(std::decay_t const& value) + { + object_[sfIndexes] = value; + return *this; + } + + /** + * @brief Set sfRootIndex (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setRootIndex(std::decay_t const& value) + { + object_[sfRootIndex] = value; + return *this; + } + + /** + * @brief Set sfIndexNext (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setIndexNext(std::decay_t const& value) + { + object_[sfIndexNext] = value; + return *this; + } + + /** + * @brief Set sfIndexPrevious (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setIndexPrevious(std::decay_t const& value) + { + object_[sfIndexPrevious] = value; + return *this; + } + + /** + * @brief Set sfNFTokenID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setNFTokenID(std::decay_t const& value) + { + object_[sfNFTokenID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DirectoryNodeBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Build and return the completed DirectoryNode wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + DirectoryNode + build(uint256 const& index) + { + return DirectoryNode{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Escrow.h b/include/xrpl/protocol_autogen/ledger_entries/Escrow.h new file mode 100644 index 0000000000..fd15b2a713 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Escrow.h @@ -0,0 +1,554 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class EscrowBuilder; + +/** + * @brief Ledger Entry: Escrow + * + * Type: ltESCROW (0x0075) + * RPC Name: escrow + * + * Immutable wrapper around SLE providing type-safe field access. + * Use EscrowBuilder to construct new ledger entries. + */ +class Escrow : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltESCROW; + + /** + * @brief Construct a Escrow ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Escrow(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Escrow"); + } + } + + // 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 sfSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSequence() const + { + if (hasSequence()) + return this->sle_->at(sfSequence); + return std::nullopt; + } + + /** + * @brief Check if sfSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSequence() const + { + return this->sle_->isFieldPresent(sfSequence); + } + + /** + * @brief Get sfDestination (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getDestination() const + { + return this->sle_->at(sfDestination); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->sle_->at(sfAmount); + } + + /** + * @brief Get sfCondition (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCondition() const + { + if (hasCondition()) + return this->sle_->at(sfCondition); + return std::nullopt; + } + + /** + * @brief Check if sfCondition is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCondition() const + { + return this->sle_->isFieldPresent(sfCondition); + } + + /** + * @brief Get sfCancelAfter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCancelAfter() const + { + if (hasCancelAfter()) + return this->sle_->at(sfCancelAfter); + return std::nullopt; + } + + /** + * @brief Check if sfCancelAfter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCancelAfter() const + { + return this->sle_->isFieldPresent(sfCancelAfter); + } + + /** + * @brief Get sfFinishAfter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getFinishAfter() const + { + if (hasFinishAfter()) + return this->sle_->at(sfFinishAfter); + return std::nullopt; + } + + /** + * @brief Check if sfFinishAfter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasFinishAfter() const + { + return this->sle_->isFieldPresent(sfFinishAfter); + } + + /** + * @brief Get sfSourceTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSourceTag() const + { + if (hasSourceTag()) + return this->sle_->at(sfSourceTag); + return std::nullopt; + } + + /** + * @brief Check if sfSourceTag is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSourceTag() const + { + return this->sle_->isFieldPresent(sfSourceTag); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDestinationTag() const + { + if (hasDestinationTag()) + return this->sle_->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->sle_->isFieldPresent(sfDestinationTag); + } + + /** + * @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 Get sfDestinationNode (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDestinationNode() const + { + if (hasDestinationNode()) + return this->sle_->at(sfDestinationNode); + return std::nullopt; + } + + /** + * @brief Check if sfDestinationNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDestinationNode() const + { + return this->sle_->isFieldPresent(sfDestinationNode); + } + + /** + * @brief Get sfTransferRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferRate() const + { + if (hasTransferRate()) + return this->sle_->at(sfTransferRate); + return std::nullopt; + } + + /** + * @brief Check if sfTransferRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferRate() const + { + return this->sle_->isFieldPresent(sfTransferRate); + } + + /** + * @brief Get sfIssuerNode (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getIssuerNode() const + { + if (hasIssuerNode()) + return this->sle_->at(sfIssuerNode); + return std::nullopt; + } + + /** + * @brief Check if sfIssuerNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasIssuerNode() const + { + return this->sle_->isFieldPresent(sfIssuerNode); + } +}; + +/** + * @brief Builder for Escrow ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class EscrowBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new EscrowBuilder with required fields. + * @param account The sfAccount field value. + * @param destination The sfDestination field value. + * @param amount The sfAmount field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + EscrowBuilder(std::decay_t const& account,std::decay_t const& destination,std::decay_t const& amount,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltESCROW) + { + setAccount(account); + setDestination(destination); + setAmount(amount); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a EscrowBuilder 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. + */ + EscrowBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltESCROW) + { + throw std::runtime_error("Invalid ledger entry type for Escrow"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfCondition (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setCondition(std::decay_t const& value) + { + object_[sfCondition] = value; + return *this; + } + + /** + * @brief Set sfCancelAfter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setCancelAfter(std::decay_t const& value) + { + object_[sfCancelAfter] = value; + return *this; + } + + /** + * @brief Set sfFinishAfter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setFinishAfter(std::decay_t const& value) + { + object_[sfFinishAfter] = value; + return *this; + } + + /** + * @brief Set sfSourceTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setSourceTag(std::decay_t const& value) + { + object_[sfSourceTag] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfDestinationNode (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setDestinationNode(std::decay_t const& value) + { + object_[sfDestinationNode] = value; + return *this; + } + + /** + * @brief Set sfTransferRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setTransferRate(std::decay_t const& value) + { + object_[sfTransferRate] = value; + return *this; + } + + /** + * @brief Set sfIssuerNode (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowBuilder& + setIssuerNode(std::decay_t const& value) + { + object_[sfIssuerNode] = value; + return *this; + } + + /** + * @brief Build and return the completed Escrow wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Escrow + build(uint256 const& index) + { + return Escrow{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/FeeSettings.h b/include/xrpl/protocol_autogen/ledger_entries/FeeSettings.h new file mode 100644 index 0000000000..e3c9ca0091 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/FeeSettings.h @@ -0,0 +1,410 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class FeeSettingsBuilder; + +/** + * @brief Ledger Entry: FeeSettings + * + * Type: ltFEE_SETTINGS (0x0073) + * RPC Name: fee + * + * Immutable wrapper around SLE providing type-safe field access. + * Use FeeSettingsBuilder to construct new ledger entries. + */ +class FeeSettings : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltFEE_SETTINGS; + + /** + * @brief Construct a FeeSettings ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit FeeSettings(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for FeeSettings"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfBaseFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBaseFee() const + { + if (hasBaseFee()) + return this->sle_->at(sfBaseFee); + return std::nullopt; + } + + /** + * @brief Check if sfBaseFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBaseFee() const + { + return this->sle_->isFieldPresent(sfBaseFee); + } + + /** + * @brief Get sfReferenceFeeUnits (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReferenceFeeUnits() const + { + if (hasReferenceFeeUnits()) + return this->sle_->at(sfReferenceFeeUnits); + return std::nullopt; + } + + /** + * @brief Check if sfReferenceFeeUnits is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReferenceFeeUnits() const + { + return this->sle_->isFieldPresent(sfReferenceFeeUnits); + } + + /** + * @brief Get sfReserveBase (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveBase() const + { + if (hasReserveBase()) + return this->sle_->at(sfReserveBase); + return std::nullopt; + } + + /** + * @brief Check if sfReserveBase is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveBase() const + { + return this->sle_->isFieldPresent(sfReserveBase); + } + + /** + * @brief Get sfReserveIncrement (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveIncrement() const + { + if (hasReserveIncrement()) + return this->sle_->at(sfReserveIncrement); + return std::nullopt; + } + + /** + * @brief Check if sfReserveIncrement is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveIncrement() const + { + return this->sle_->isFieldPresent(sfReserveIncrement); + } + + /** + * @brief Get sfBaseFeeDrops (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBaseFeeDrops() const + { + if (hasBaseFeeDrops()) + return this->sle_->at(sfBaseFeeDrops); + return std::nullopt; + } + + /** + * @brief Check if sfBaseFeeDrops is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBaseFeeDrops() const + { + return this->sle_->isFieldPresent(sfBaseFeeDrops); + } + + /** + * @brief Get sfReserveBaseDrops (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveBaseDrops() const + { + if (hasReserveBaseDrops()) + return this->sle_->at(sfReserveBaseDrops); + return std::nullopt; + } + + /** + * @brief Check if sfReserveBaseDrops is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveBaseDrops() const + { + return this->sle_->isFieldPresent(sfReserveBaseDrops); + } + + /** + * @brief Get sfReserveIncrementDrops (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveIncrementDrops() const + { + if (hasReserveIncrementDrops()) + return this->sle_->at(sfReserveIncrementDrops); + return std::nullopt; + } + + /** + * @brief Check if sfReserveIncrementDrops is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveIncrementDrops() const + { + return this->sle_->isFieldPresent(sfReserveIncrementDrops); + } + + /** + * @brief Get sfPreviousTxnID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnID() const + { + if (hasPreviousTxnID()) + return this->sle_->at(sfPreviousTxnID); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnID() const + { + return this->sle_->isFieldPresent(sfPreviousTxnID); + } + + /** + * @brief Get sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnLgrSeq() const + { + if (hasPreviousTxnLgrSeq()) + return this->sle_->at(sfPreviousTxnLgrSeq); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnLgrSeq is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnLgrSeq() const + { + return this->sle_->isFieldPresent(sfPreviousTxnLgrSeq); + } +}; + +/** + * @brief Builder for FeeSettings ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class FeeSettingsBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new FeeSettingsBuilder with required fields. + */ + FeeSettingsBuilder() + : LedgerEntryBuilderBase(ltFEE_SETTINGS) + { + } + + /** + * @brief Construct a FeeSettingsBuilder 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. + */ + FeeSettingsBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltFEE_SETTINGS) + { + throw std::runtime_error("Invalid ledger entry type for FeeSettings"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfBaseFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setBaseFee(std::decay_t const& value) + { + object_[sfBaseFee] = value; + return *this; + } + + /** + * @brief Set sfReferenceFeeUnits (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setReferenceFeeUnits(std::decay_t const& value) + { + object_[sfReferenceFeeUnits] = value; + return *this; + } + + /** + * @brief Set sfReserveBase (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setReserveBase(std::decay_t const& value) + { + object_[sfReserveBase] = value; + return *this; + } + + /** + * @brief Set sfReserveIncrement (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setReserveIncrement(std::decay_t const& value) + { + object_[sfReserveIncrement] = value; + return *this; + } + + /** + * @brief Set sfBaseFeeDrops (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setBaseFeeDrops(std::decay_t const& value) + { + object_[sfBaseFeeDrops] = value; + return *this; + } + + /** + * @brief Set sfReserveBaseDrops (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setReserveBaseDrops(std::decay_t const& value) + { + object_[sfReserveBaseDrops] = value; + return *this; + } + + /** + * @brief Set sfReserveIncrementDrops (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setReserveIncrementDrops(std::decay_t const& value) + { + object_[sfReserveIncrementDrops] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + FeeSettingsBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed FeeSettings wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + FeeSettings + build(uint256 const& index) + { + return FeeSettings{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/LedgerHashes.h b/include/xrpl/protocol_autogen/ledger_entries/LedgerHashes.h new file mode 100644 index 0000000000..c95ca303ba --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/LedgerHashes.h @@ -0,0 +1,189 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class LedgerHashesBuilder; + +/** + * @brief Ledger Entry: LedgerHashes + * + * Type: ltLEDGER_HASHES (0x0068) + * RPC Name: hashes + * + * Immutable wrapper around SLE providing type-safe field access. + * Use LedgerHashesBuilder to construct new ledger entries. + */ +class LedgerHashes : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltLEDGER_HASHES; + + /** + * @brief Construct a LedgerHashes ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit LedgerHashes(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for LedgerHashes"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfFirstLedgerSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getFirstLedgerSequence() const + { + if (hasFirstLedgerSequence()) + return this->sle_->at(sfFirstLedgerSequence); + return std::nullopt; + } + + /** + * @brief Check if sfFirstLedgerSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasFirstLedgerSequence() const + { + return this->sle_->isFieldPresent(sfFirstLedgerSequence); + } + + /** + * @brief Get sfLastLedgerSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLastLedgerSequence() const + { + if (hasLastLedgerSequence()) + return this->sle_->at(sfLastLedgerSequence); + return std::nullopt; + } + + /** + * @brief Check if sfLastLedgerSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLastLedgerSequence() const + { + return this->sle_->isFieldPresent(sfLastLedgerSequence); + } + + /** + * @brief Get sfHashes (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VECTOR256::type::value_type + getHashes() const + { + return this->sle_->at(sfHashes); + } +}; + +/** + * @brief Builder for LedgerHashes ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class LedgerHashesBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new LedgerHashesBuilder with required fields. + * @param hashes The sfHashes field value. + */ + LedgerHashesBuilder(std::decay_t const& hashes) + : LedgerEntryBuilderBase(ltLEDGER_HASHES) + { + setHashes(hashes); + } + + /** + * @brief Construct a LedgerHashesBuilder 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. + */ + LedgerHashesBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltLEDGER_HASHES) + { + throw std::runtime_error("Invalid ledger entry type for LedgerHashes"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfFirstLedgerSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LedgerHashesBuilder& + setFirstLedgerSequence(std::decay_t const& value) + { + object_[sfFirstLedgerSequence] = value; + return *this; + } + + /** + * @brief Set sfLastLedgerSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LedgerHashesBuilder& + setLastLedgerSequence(std::decay_t const& value) + { + object_[sfLastLedgerSequence] = value; + return *this; + } + + /** + * @brief Set sfHashes (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LedgerHashesBuilder& + setHashes(std::decay_t const& value) + { + object_[sfHashes] = value; + return *this; + } + + /** + * @brief Build and return the completed LedgerHashes wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + LedgerHashes + build(uint256 const& index) + { + return LedgerHashes{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Loan.h b/include/xrpl/protocol_autogen/ledger_entries/Loan.h new file mode 100644 index 0000000000..73b37ea892 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Loan.h @@ -0,0 +1,930 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class LoanBuilder; + +/** + * @brief Ledger Entry: Loan + * + * Type: ltLOAN (0x0089) + * RPC Name: loan + * + * Immutable wrapper around SLE providing type-safe field access. + * Use LoanBuilder to construct new ledger entries. + */ +class Loan : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltLOAN; + + /** + * @brief Construct a Loan ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Loan(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Loan"); + } + } + + // 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 sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfLoanBrokerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getLoanBrokerNode() const + { + return this->sle_->at(sfLoanBrokerNode); + } + + /** + * @brief Get sfLoanBrokerID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanBrokerID() const + { + return this->sle_->at(sfLoanBrokerID); + } + + /** + * @brief Get sfLoanSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getLoanSequence() const + { + return this->sle_->at(sfLoanSequence); + } + + /** + * @brief Get sfBorrower (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getBorrower() const + { + return this->sle_->at(sfBorrower); + } + + /** + * @brief Get sfLoanOriginationFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanOriginationFee() const + { + if (hasLoanOriginationFee()) + return this->sle_->at(sfLoanOriginationFee); + return std::nullopt; + } + + /** + * @brief Check if sfLoanOriginationFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanOriginationFee() const + { + return this->sle_->isFieldPresent(sfLoanOriginationFee); + } + + /** + * @brief Get sfLoanServiceFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanServiceFee() const + { + if (hasLoanServiceFee()) + return this->sle_->at(sfLoanServiceFee); + return std::nullopt; + } + + /** + * @brief Check if sfLoanServiceFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanServiceFee() const + { + return this->sle_->isFieldPresent(sfLoanServiceFee); + } + + /** + * @brief Get sfLatePaymentFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLatePaymentFee() const + { + if (hasLatePaymentFee()) + return this->sle_->at(sfLatePaymentFee); + return std::nullopt; + } + + /** + * @brief Check if sfLatePaymentFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLatePaymentFee() const + { + return this->sle_->isFieldPresent(sfLatePaymentFee); + } + + /** + * @brief Get sfClosePaymentFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getClosePaymentFee() const + { + if (hasClosePaymentFee()) + return this->sle_->at(sfClosePaymentFee); + return std::nullopt; + } + + /** + * @brief Check if sfClosePaymentFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasClosePaymentFee() const + { + return this->sle_->isFieldPresent(sfClosePaymentFee); + } + + /** + * @brief Get sfOverpaymentFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOverpaymentFee() const + { + if (hasOverpaymentFee()) + return this->sle_->at(sfOverpaymentFee); + return std::nullopt; + } + + /** + * @brief Check if sfOverpaymentFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOverpaymentFee() const + { + return this->sle_->isFieldPresent(sfOverpaymentFee); + } + + /** + * @brief Get sfInterestRate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getInterestRate() const + { + if (hasInterestRate()) + return this->sle_->at(sfInterestRate); + return std::nullopt; + } + + /** + * @brief Check if sfInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasInterestRate() const + { + return this->sle_->isFieldPresent(sfInterestRate); + } + + /** + * @brief Get sfLateInterestRate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLateInterestRate() const + { + if (hasLateInterestRate()) + return this->sle_->at(sfLateInterestRate); + return std::nullopt; + } + + /** + * @brief Check if sfLateInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLateInterestRate() const + { + return this->sle_->isFieldPresent(sfLateInterestRate); + } + + /** + * @brief Get sfCloseInterestRate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCloseInterestRate() const + { + if (hasCloseInterestRate()) + return this->sle_->at(sfCloseInterestRate); + return std::nullopt; + } + + /** + * @brief Check if sfCloseInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCloseInterestRate() const + { + return this->sle_->isFieldPresent(sfCloseInterestRate); + } + + /** + * @brief Get sfOverpaymentInterestRate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOverpaymentInterestRate() const + { + if (hasOverpaymentInterestRate()) + return this->sle_->at(sfOverpaymentInterestRate); + return std::nullopt; + } + + /** + * @brief Check if sfOverpaymentInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOverpaymentInterestRate() const + { + return this->sle_->isFieldPresent(sfOverpaymentInterestRate); + } + + /** + * @brief Get sfStartDate (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getStartDate() const + { + return this->sle_->at(sfStartDate); + } + + /** + * @brief Get sfPaymentInterval (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getPaymentInterval() const + { + return this->sle_->at(sfPaymentInterval); + } + + /** + * @brief Get sfGracePeriod (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getGracePeriod() const + { + if (hasGracePeriod()) + return this->sle_->at(sfGracePeriod); + return std::nullopt; + } + + /** + * @brief Check if sfGracePeriod is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasGracePeriod() const + { + return this->sle_->isFieldPresent(sfGracePeriod); + } + + /** + * @brief Get sfPreviousPaymentDueDate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousPaymentDueDate() const + { + if (hasPreviousPaymentDueDate()) + return this->sle_->at(sfPreviousPaymentDueDate); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousPaymentDueDate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousPaymentDueDate() const + { + return this->sle_->isFieldPresent(sfPreviousPaymentDueDate); + } + + /** + * @brief Get sfNextPaymentDueDate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNextPaymentDueDate() const + { + if (hasNextPaymentDueDate()) + return this->sle_->at(sfNextPaymentDueDate); + return std::nullopt; + } + + /** + * @brief Check if sfNextPaymentDueDate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNextPaymentDueDate() const + { + return this->sle_->isFieldPresent(sfNextPaymentDueDate); + } + + /** + * @brief Get sfPaymentRemaining (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPaymentRemaining() const + { + if (hasPaymentRemaining()) + return this->sle_->at(sfPaymentRemaining); + return std::nullopt; + } + + /** + * @brief Check if sfPaymentRemaining is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPaymentRemaining() const + { + return this->sle_->isFieldPresent(sfPaymentRemaining); + } + + /** + * @brief Get sfPeriodicPayment (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_NUMBER::type::value_type + getPeriodicPayment() const + { + return this->sle_->at(sfPeriodicPayment); + } + + /** + * @brief Get sfPrincipalOutstanding (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPrincipalOutstanding() const + { + if (hasPrincipalOutstanding()) + return this->sle_->at(sfPrincipalOutstanding); + return std::nullopt; + } + + /** + * @brief Check if sfPrincipalOutstanding is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPrincipalOutstanding() const + { + return this->sle_->isFieldPresent(sfPrincipalOutstanding); + } + + /** + * @brief Get sfTotalValueOutstanding (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTotalValueOutstanding() const + { + if (hasTotalValueOutstanding()) + return this->sle_->at(sfTotalValueOutstanding); + return std::nullopt; + } + + /** + * @brief Check if sfTotalValueOutstanding is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTotalValueOutstanding() const + { + return this->sle_->isFieldPresent(sfTotalValueOutstanding); + } + + /** + * @brief Get sfManagementFeeOutstanding (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getManagementFeeOutstanding() const + { + if (hasManagementFeeOutstanding()) + return this->sle_->at(sfManagementFeeOutstanding); + return std::nullopt; + } + + /** + * @brief Check if sfManagementFeeOutstanding is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasManagementFeeOutstanding() const + { + return this->sle_->isFieldPresent(sfManagementFeeOutstanding); + } + + /** + * @brief Get sfLoanScale (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanScale() const + { + if (hasLoanScale()) + return this->sle_->at(sfLoanScale); + return std::nullopt; + } + + /** + * @brief Check if sfLoanScale is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanScale() const + { + return this->sle_->isFieldPresent(sfLoanScale); + } +}; + +/** + * @brief Builder for Loan ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class LoanBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new LoanBuilder with required fields. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + * @param ownerNode The sfOwnerNode field value. + * @param loanBrokerNode The sfLoanBrokerNode field value. + * @param loanBrokerID The sfLoanBrokerID field value. + * @param loanSequence The sfLoanSequence field value. + * @param borrower The sfBorrower field value. + * @param startDate The sfStartDate field value. + * @param paymentInterval The sfPaymentInterval field value. + * @param periodicPayment The sfPeriodicPayment field value. + */ + LoanBuilder(std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq,std::decay_t const& ownerNode,std::decay_t const& loanBrokerNode,std::decay_t const& loanBrokerID,std::decay_t const& loanSequence,std::decay_t const& borrower,std::decay_t const& startDate,std::decay_t const& paymentInterval,std::decay_t const& periodicPayment) + : LedgerEntryBuilderBase(ltLOAN) + { + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + setOwnerNode(ownerNode); + setLoanBrokerNode(loanBrokerNode); + setLoanBrokerID(loanBrokerID); + setLoanSequence(loanSequence); + setBorrower(borrower); + setStartDate(startDate); + setPaymentInterval(paymentInterval); + setPeriodicPayment(periodicPayment); + } + + /** + * @brief Construct a LoanBuilder 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. + */ + LoanBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltLOAN) + { + throw std::runtime_error("Invalid ledger entry type for Loan"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfLoanBrokerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLoanBrokerNode(std::decay_t const& value) + { + object_[sfLoanBrokerNode] = value; + return *this; + } + + /** + * @brief Set sfLoanBrokerID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Set sfLoanSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLoanSequence(std::decay_t const& value) + { + object_[sfLoanSequence] = value; + return *this; + } + + /** + * @brief Set sfBorrower (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setBorrower(std::decay_t const& value) + { + object_[sfBorrower] = value; + return *this; + } + + /** + * @brief Set sfLoanOriginationFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLoanOriginationFee(std::decay_t const& value) + { + object_[sfLoanOriginationFee] = value; + return *this; + } + + /** + * @brief Set sfLoanServiceFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLoanServiceFee(std::decay_t const& value) + { + object_[sfLoanServiceFee] = value; + return *this; + } + + /** + * @brief Set sfLatePaymentFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLatePaymentFee(std::decay_t const& value) + { + object_[sfLatePaymentFee] = value; + return *this; + } + + /** + * @brief Set sfClosePaymentFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setClosePaymentFee(std::decay_t const& value) + { + object_[sfClosePaymentFee] = value; + return *this; + } + + /** + * @brief Set sfOverpaymentFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setOverpaymentFee(std::decay_t const& value) + { + object_[sfOverpaymentFee] = value; + return *this; + } + + /** + * @brief Set sfInterestRate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setInterestRate(std::decay_t const& value) + { + object_[sfInterestRate] = value; + return *this; + } + + /** + * @brief Set sfLateInterestRate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLateInterestRate(std::decay_t const& value) + { + object_[sfLateInterestRate] = value; + return *this; + } + + /** + * @brief Set sfCloseInterestRate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setCloseInterestRate(std::decay_t const& value) + { + object_[sfCloseInterestRate] = value; + return *this; + } + + /** + * @brief Set sfOverpaymentInterestRate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setOverpaymentInterestRate(std::decay_t const& value) + { + object_[sfOverpaymentInterestRate] = value; + return *this; + } + + /** + * @brief Set sfStartDate (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setStartDate(std::decay_t const& value) + { + object_[sfStartDate] = value; + return *this; + } + + /** + * @brief Set sfPaymentInterval (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPaymentInterval(std::decay_t const& value) + { + object_[sfPaymentInterval] = value; + return *this; + } + + /** + * @brief Set sfGracePeriod (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setGracePeriod(std::decay_t const& value) + { + object_[sfGracePeriod] = value; + return *this; + } + + /** + * @brief Set sfPreviousPaymentDueDate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPreviousPaymentDueDate(std::decay_t const& value) + { + object_[sfPreviousPaymentDueDate] = value; + return *this; + } + + /** + * @brief Set sfNextPaymentDueDate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setNextPaymentDueDate(std::decay_t const& value) + { + object_[sfNextPaymentDueDate] = value; + return *this; + } + + /** + * @brief Set sfPaymentRemaining (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPaymentRemaining(std::decay_t const& value) + { + object_[sfPaymentRemaining] = value; + return *this; + } + + /** + * @brief Set sfPeriodicPayment (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPeriodicPayment(std::decay_t const& value) + { + object_[sfPeriodicPayment] = value; + return *this; + } + + /** + * @brief Set sfPrincipalOutstanding (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setPrincipalOutstanding(std::decay_t const& value) + { + object_[sfPrincipalOutstanding] = value; + return *this; + } + + /** + * @brief Set sfTotalValueOutstanding (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setTotalValueOutstanding(std::decay_t const& value) + { + object_[sfTotalValueOutstanding] = value; + return *this; + } + + /** + * @brief Set sfManagementFeeOutstanding (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setManagementFeeOutstanding(std::decay_t const& value) + { + object_[sfManagementFeeOutstanding] = value; + return *this; + } + + /** + * @brief Set sfLoanScale (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBuilder& + setLoanScale(std::decay_t const& value) + { + object_[sfLoanScale] = value; + return *this; + } + + /** + * @brief Build and return the completed Loan wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Loan + build(uint256 const& index) + { + return Loan{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/LoanBroker.h b/include/xrpl/protocol_autogen/ledger_entries/LoanBroker.h new file mode 100644 index 0000000000..99083d6fce --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/LoanBroker.h @@ -0,0 +1,591 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class LoanBrokerBuilder; + +/** + * @brief Ledger Entry: LoanBroker + * + * Type: ltLOAN_BROKER (0x0088) + * RPC Name: loan_broker + * + * Immutable wrapper around SLE providing type-safe field access. + * Use LoanBrokerBuilder to construct new ledger entries. + */ +class LoanBroker : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltLOAN_BROKER; + + /** + * @brief Construct a LoanBroker ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit LoanBroker(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for LoanBroker"); + } + } + + // 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 sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfVaultNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getVaultNode() const + { + return this->sle_->at(sfVaultNode); + } + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->sle_->at(sfVaultID); + } + + /** + * @brief Get sfAccount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getAccount() const + { + return this->sle_->at(sfAccount); + } + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->sle_->at(sfOwner); + } + + /** + * @brief Get sfLoanSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getLoanSequence() const + { + return this->sle_->at(sfLoanSequence); + } + + /** + * @brief Get sfData (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + return this->sle_->at(sfData); + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->sle_->isFieldPresent(sfData); + } + + /** + * @brief Get sfManagementFeeRate (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getManagementFeeRate() const + { + if (hasManagementFeeRate()) + return this->sle_->at(sfManagementFeeRate); + return std::nullopt; + } + + /** + * @brief Check if sfManagementFeeRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasManagementFeeRate() const + { + return this->sle_->isFieldPresent(sfManagementFeeRate); + } + + /** + * @brief Get sfOwnerCount (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwnerCount() const + { + if (hasOwnerCount()) + return this->sle_->at(sfOwnerCount); + return std::nullopt; + } + + /** + * @brief Check if sfOwnerCount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwnerCount() const + { + return this->sle_->isFieldPresent(sfOwnerCount); + } + + /** + * @brief Get sfDebtTotal (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDebtTotal() const + { + if (hasDebtTotal()) + return this->sle_->at(sfDebtTotal); + return std::nullopt; + } + + /** + * @brief Check if sfDebtTotal is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDebtTotal() const + { + return this->sle_->isFieldPresent(sfDebtTotal); + } + + /** + * @brief Get sfDebtMaximum (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDebtMaximum() const + { + if (hasDebtMaximum()) + return this->sle_->at(sfDebtMaximum); + return std::nullopt; + } + + /** + * @brief Check if sfDebtMaximum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDebtMaximum() const + { + return this->sle_->isFieldPresent(sfDebtMaximum); + } + + /** + * @brief Get sfCoverAvailable (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCoverAvailable() const + { + if (hasCoverAvailable()) + return this->sle_->at(sfCoverAvailable); + return std::nullopt; + } + + /** + * @brief Check if sfCoverAvailable is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCoverAvailable() const + { + return this->sle_->isFieldPresent(sfCoverAvailable); + } + + /** + * @brief Get sfCoverRateMinimum (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCoverRateMinimum() const + { + if (hasCoverRateMinimum()) + return this->sle_->at(sfCoverRateMinimum); + return std::nullopt; + } + + /** + * @brief Check if sfCoverRateMinimum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCoverRateMinimum() const + { + return this->sle_->isFieldPresent(sfCoverRateMinimum); + } + + /** + * @brief Get sfCoverRateLiquidation (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCoverRateLiquidation() const + { + if (hasCoverRateLiquidation()) + return this->sle_->at(sfCoverRateLiquidation); + return std::nullopt; + } + + /** + * @brief Check if sfCoverRateLiquidation is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCoverRateLiquidation() const + { + return this->sle_->isFieldPresent(sfCoverRateLiquidation); + } +}; + +/** + * @brief Builder for LoanBroker ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class LoanBrokerBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new LoanBrokerBuilder with required fields. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + * @param sequence The sfSequence field value. + * @param ownerNode The sfOwnerNode field value. + * @param vaultNode The sfVaultNode field value. + * @param vaultID The sfVaultID field value. + * @param account The sfAccount field value. + * @param owner The sfOwner field value. + * @param loanSequence The sfLoanSequence field value. + */ + LoanBrokerBuilder(std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq,std::decay_t const& sequence,std::decay_t const& ownerNode,std::decay_t const& vaultNode,std::decay_t const& vaultID,std::decay_t const& account,std::decay_t const& owner,std::decay_t const& loanSequence) + : LedgerEntryBuilderBase(ltLOAN_BROKER) + { + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + setSequence(sequence); + setOwnerNode(ownerNode); + setVaultNode(vaultNode); + setVaultID(vaultID); + setAccount(account); + setOwner(owner); + setLoanSequence(loanSequence); + } + + /** + * @brief Construct a LoanBrokerBuilder 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. + */ + LoanBrokerBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltLOAN_BROKER) + { + throw std::runtime_error("Invalid ledger entry type for LoanBroker"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfVaultNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setVaultNode(std::decay_t const& value) + { + object_[sfVaultNode] = value; + return *this; + } + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfLoanSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setLoanSequence(std::decay_t const& value) + { + object_[sfLoanSequence] = value; + return *this; + } + + /** + * @brief Set sfData (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Set sfManagementFeeRate (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setManagementFeeRate(std::decay_t const& value) + { + object_[sfManagementFeeRate] = value; + return *this; + } + + /** + * @brief Set sfOwnerCount (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setOwnerCount(std::decay_t const& value) + { + object_[sfOwnerCount] = value; + return *this; + } + + /** + * @brief Set sfDebtTotal (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setDebtTotal(std::decay_t const& value) + { + object_[sfDebtTotal] = value; + return *this; + } + + /** + * @brief Set sfDebtMaximum (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setDebtMaximum(std::decay_t const& value) + { + object_[sfDebtMaximum] = value; + return *this; + } + + /** + * @brief Set sfCoverAvailable (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setCoverAvailable(std::decay_t const& value) + { + object_[sfCoverAvailable] = value; + return *this; + } + + /** + * @brief Set sfCoverRateMinimum (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setCoverRateMinimum(std::decay_t const& value) + { + object_[sfCoverRateMinimum] = value; + return *this; + } + + /** + * @brief Set sfCoverRateLiquidation (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + LoanBrokerBuilder& + setCoverRateLiquidation(std::decay_t const& value) + { + object_[sfCoverRateLiquidation] = value; + return *this; + } + + /** + * @brief Build and return the completed LoanBroker wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + LoanBroker + build(uint256 const& index) + { + return LoanBroker{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/MPToken.h b/include/xrpl/protocol_autogen/ledger_entries/MPToken.h new file mode 100644 index 0000000000..d11a8effd3 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/MPToken.h @@ -0,0 +1,285 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class MPTokenBuilder; + +/** + * @brief Ledger Entry: MPToken + * + * Type: ltMPTOKEN (0x007f) + * RPC Name: mptoken + * + * Immutable wrapper around SLE providing type-safe field access. + * Use MPTokenBuilder to construct new ledger entries. + */ +class MPToken : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltMPTOKEN; + + /** + * @brief Construct a MPToken ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit MPToken(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for MPToken"); + } + } + + // 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 sfMPTokenIssuanceID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT192::type::value_type + getMPTokenIssuanceID() const + { + return this->sle_->at(sfMPTokenIssuanceID); + } + + /** + * @brief Get sfMPTAmount (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMPTAmount() const + { + if (hasMPTAmount()) + return this->sle_->at(sfMPTAmount); + return std::nullopt; + } + + /** + * @brief Check if sfMPTAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMPTAmount() const + { + return this->sle_->isFieldPresent(sfMPTAmount); + } + + /** + * @brief Get sfLockedAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLockedAmount() const + { + if (hasLockedAmount()) + return this->sle_->at(sfLockedAmount); + return std::nullopt; + } + + /** + * @brief Check if sfLockedAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLockedAmount() const + { + return this->sle_->isFieldPresent(sfLockedAmount); + } + + /** + * @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 MPToken ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class MPTokenBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new MPTokenBuilder with required fields. + * @param account The sfAccount field value. + * @param mPTokenIssuanceID The sfMPTokenIssuanceID field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + MPTokenBuilder(std::decay_t const& account,std::decay_t const& mPTokenIssuanceID,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltMPTOKEN) + { + setAccount(account); + setMPTokenIssuanceID(mPTokenIssuanceID); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a MPTokenBuilder 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. + */ + MPTokenBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltMPTOKEN) + { + throw std::runtime_error("Invalid ledger entry type for MPToken"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfMPTokenIssuanceID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setMPTokenIssuanceID(std::decay_t const& value) + { + object_[sfMPTokenIssuanceID] = value; + return *this; + } + + /** + * @brief Set sfMPTAmount (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setMPTAmount(std::decay_t const& value) + { + object_[sfMPTAmount] = value; + return *this; + } + + /** + * @brief Set sfLockedAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setLockedAmount(std::decay_t const& value) + { + object_[sfLockedAmount] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed MPToken wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + MPToken + build(uint256 const& index) + { + return MPToken{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/MPTokenIssuance.h b/include/xrpl/protocol_autogen/ledger_entries/MPTokenIssuance.h new file mode 100644 index 0000000000..23b8a05015 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/MPTokenIssuance.h @@ -0,0 +1,484 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class MPTokenIssuanceBuilder; + +/** + * @brief Ledger Entry: MPTokenIssuance + * + * Type: ltMPTOKEN_ISSUANCE (0x007e) + * RPC Name: mpt_issuance + * + * Immutable wrapper around SLE providing type-safe field access. + * Use MPTokenIssuanceBuilder to construct new ledger entries. + */ +class MPTokenIssuance : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltMPTOKEN_ISSUANCE; + + /** + * @brief Construct a MPTokenIssuance ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit MPTokenIssuance(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for MPTokenIssuance"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfIssuer (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getIssuer() const + { + return this->sle_->at(sfIssuer); + } + + /** + * @brief Get sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfTransferFee (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferFee() const + { + if (hasTransferFee()) + return this->sle_->at(sfTransferFee); + return std::nullopt; + } + + /** + * @brief Check if sfTransferFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferFee() const + { + return this->sle_->isFieldPresent(sfTransferFee); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfAssetScale (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetScale() const + { + if (hasAssetScale()) + return this->sle_->at(sfAssetScale); + return std::nullopt; + } + + /** + * @brief Check if sfAssetScale is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetScale() const + { + return this->sle_->isFieldPresent(sfAssetScale); + } + + /** + * @brief Get sfMaximumAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMaximumAmount() const + { + if (hasMaximumAmount()) + return this->sle_->at(sfMaximumAmount); + return std::nullopt; + } + + /** + * @brief Check if sfMaximumAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMaximumAmount() const + { + return this->sle_->isFieldPresent(sfMaximumAmount); + } + + /** + * @brief Get sfOutstandingAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOutstandingAmount() const + { + return this->sle_->at(sfOutstandingAmount); + } + + /** + * @brief Get sfLockedAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLockedAmount() const + { + if (hasLockedAmount()) + return this->sle_->at(sfLockedAmount); + return std::nullopt; + } + + /** + * @brief Check if sfLockedAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLockedAmount() const + { + return this->sle_->isFieldPresent(sfLockedAmount); + } + + /** + * @brief Get sfMPTokenMetadata (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMPTokenMetadata() const + { + if (hasMPTokenMetadata()) + return this->sle_->at(sfMPTokenMetadata); + return std::nullopt; + } + + /** + * @brief Check if sfMPTokenMetadata is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMPTokenMetadata() const + { + return this->sle_->isFieldPresent(sfMPTokenMetadata); + } + + /** + * @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 sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + return this->sle_->at(sfDomainID); + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->sle_->isFieldPresent(sfDomainID); + } + + /** + * @brief Get sfMutableFlags (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMutableFlags() const + { + if (hasMutableFlags()) + return this->sle_->at(sfMutableFlags); + return std::nullopt; + } + + /** + * @brief Check if sfMutableFlags is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMutableFlags() const + { + return this->sle_->isFieldPresent(sfMutableFlags); + } +}; + +/** + * @brief Builder for MPTokenIssuance ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class MPTokenIssuanceBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new MPTokenIssuanceBuilder with required fields. + * @param issuer The sfIssuer field value. + * @param sequence The sfSequence field value. + * @param ownerNode The sfOwnerNode field value. + * @param outstandingAmount The sfOutstandingAmount field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + MPTokenIssuanceBuilder(std::decay_t const& issuer,std::decay_t const& sequence,std::decay_t const& ownerNode,std::decay_t const& outstandingAmount,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltMPTOKEN_ISSUANCE) + { + setIssuer(issuer); + setSequence(sequence); + setOwnerNode(ownerNode); + setOutstandingAmount(outstandingAmount); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a MPTokenIssuanceBuilder 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. + */ + MPTokenIssuanceBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltMPTOKEN_ISSUANCE) + { + throw std::runtime_error("Invalid ledger entry type for MPTokenIssuance"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfIssuer (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setIssuer(std::decay_t const& value) + { + object_[sfIssuer] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfTransferFee (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setTransferFee(std::decay_t const& value) + { + object_[sfTransferFee] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfAssetScale (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setAssetScale(std::decay_t const& value) + { + object_[sfAssetScale] = value; + return *this; + } + + /** + * @brief Set sfMaximumAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setMaximumAmount(std::decay_t const& value) + { + object_[sfMaximumAmount] = value; + return *this; + } + + /** + * @brief Set sfOutstandingAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setOutstandingAmount(std::decay_t const& value) + { + object_[sfOutstandingAmount] = value; + return *this; + } + + /** + * @brief Set sfLockedAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setLockedAmount(std::decay_t const& value) + { + object_[sfLockedAmount] = value; + return *this; + } + + /** + * @brief Set sfMPTokenMetadata (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setMPTokenMetadata(std::decay_t const& value) + { + object_[sfMPTokenMetadata] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfMutableFlags (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceBuilder& + setMutableFlags(std::decay_t const& value) + { + object_[sfMutableFlags] = value; + return *this; + } + + /** + * @brief Build and return the completed MPTokenIssuance wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + MPTokenIssuance + build(uint256 const& index) + { + return MPTokenIssuance{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/NFTokenOffer.h b/include/xrpl/protocol_autogen/ledger_entries/NFTokenOffer.h new file mode 100644 index 0000000000..c500cde14c --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/NFTokenOffer.h @@ -0,0 +1,333 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class NFTokenOfferBuilder; + +/** + * @brief Ledger Entry: NFTokenOffer + * + * Type: ltNFTOKEN_OFFER (0x0037) + * RPC Name: nft_offer + * + * Immutable wrapper around SLE providing type-safe field access. + * Use NFTokenOfferBuilder to construct new ledger entries. + */ +class NFTokenOffer : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltNFTOKEN_OFFER; + + /** + * @brief Construct a NFTokenOffer ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit NFTokenOffer(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for NFTokenOffer"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->sle_->at(sfOwner); + } + + /** + * @brief Get sfNFTokenID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getNFTokenID() const + { + return this->sle_->at(sfNFTokenID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->sle_->at(sfAmount); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfNFTokenOfferNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getNFTokenOfferNode() const + { + return this->sle_->at(sfNFTokenOfferNode); + } + + /** + * @brief Get sfDestination (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDestination() const + { + if (hasDestination()) + return this->sle_->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->sle_->isFieldPresent(sfDestination); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + return this->sle_->at(sfExpiration); + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->sle_->isFieldPresent(sfExpiration); + } + + /** + * @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 NFTokenOffer ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class NFTokenOfferBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenOfferBuilder with required fields. + * @param owner The sfOwner field value. + * @param nFTokenID The sfNFTokenID field value. + * @param amount The sfAmount field value. + * @param ownerNode The sfOwnerNode field value. + * @param nFTokenOfferNode The sfNFTokenOfferNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + NFTokenOfferBuilder(std::decay_t const& owner,std::decay_t const& nFTokenID,std::decay_t const& amount,std::decay_t const& ownerNode,std::decay_t const& nFTokenOfferNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltNFTOKEN_OFFER) + { + setOwner(owner); + setNFTokenID(nFTokenID); + setAmount(amount); + setOwnerNode(ownerNode); + setNFTokenOfferNode(nFTokenOfferNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a NFTokenOfferBuilder 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. + */ + NFTokenOfferBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltNFTOKEN_OFFER) + { + throw std::runtime_error("Invalid ledger entry type for NFTokenOffer"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfNFTokenID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setNFTokenID(std::decay_t const& value) + { + object_[sfNFTokenID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfNFTokenOfferNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setNFTokenOfferNode(std::decay_t const& value) + { + object_[sfNFTokenOfferNode] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenOfferBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed NFTokenOffer wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + NFTokenOffer + build(uint256 const& index) + { + return NFTokenOffer{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/NFTokenPage.h b/include/xrpl/protocol_autogen/ledger_entries/NFTokenPage.h new file mode 100644 index 0000000000..fa8c415495 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/NFTokenPage.h @@ -0,0 +1,238 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class NFTokenPageBuilder; + +/** + * @brief Ledger Entry: NFTokenPage + * + * Type: ltNFTOKEN_PAGE (0x0050) + * RPC Name: nft_page + * + * Immutable wrapper around SLE providing type-safe field access. + * Use NFTokenPageBuilder to construct new ledger entries. + */ +class NFTokenPage : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltNFTOKEN_PAGE; + + /** + * @brief Construct a NFTokenPage ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit NFTokenPage(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for NFTokenPage"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfPreviousPageMin (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousPageMin() const + { + if (hasPreviousPageMin()) + return this->sle_->at(sfPreviousPageMin); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousPageMin is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousPageMin() const + { + return this->sle_->isFieldPresent(sfPreviousPageMin); + } + + /** + * @brief Get sfNextPageMin (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNextPageMin() const + { + if (hasNextPageMin()) + return this->sle_->at(sfNextPageMin); + return std::nullopt; + } + + /** + * @brief Check if sfNextPageMin is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNextPageMin() const + { + return this->sle_->isFieldPresent(sfNextPageMin); + } + + /** + * @brief Get sfNFTokens (soeREQUIRED) + * @note This is an untyped field (unknown). + * @return The field value. + */ + [[nodiscard]] + STArray const& + getNFTokens() const + { + return this->sle_->getFieldArray(sfNFTokens); + } + + /** + * @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 NFTokenPage ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class NFTokenPageBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenPageBuilder with required fields. + * @param nFTokens The sfNFTokens field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + NFTokenPageBuilder(STArray const& nFTokens,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltNFTOKEN_PAGE) + { + setNFTokens(nFTokens); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a NFTokenPageBuilder 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. + */ + NFTokenPageBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltNFTOKEN_PAGE) + { + throw std::runtime_error("Invalid ledger entry type for NFTokenPage"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfPreviousPageMin (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenPageBuilder& + setPreviousPageMin(std::decay_t const& value) + { + object_[sfPreviousPageMin] = value; + return *this; + } + + /** + * @brief Set sfNextPageMin (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenPageBuilder& + setNextPageMin(std::decay_t const& value) + { + object_[sfNextPageMin] = value; + return *this; + } + + /** + * @brief Set sfNFTokens (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenPageBuilder& + setNFTokens(STArray const& value) + { + object_.setFieldArray(sfNFTokens, value); + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenPageBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenPageBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed NFTokenPage wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + NFTokenPage + build(uint256 const& index) + { + return NFTokenPage{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/NegativeUNL.h b/include/xrpl/protocol_autogen/ledger_entries/NegativeUNL.h new file mode 100644 index 0000000000..8ac2db5683 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/NegativeUNL.h @@ -0,0 +1,271 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class NegativeUNLBuilder; + +/** + * @brief Ledger Entry: NegativeUNL + * + * Type: ltNEGATIVE_UNL (0x004e) + * RPC Name: nunl + * + * Immutable wrapper around SLE providing type-safe field access. + * Use NegativeUNLBuilder to construct new ledger entries. + */ +class NegativeUNL : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltNEGATIVE_UNL; + + /** + * @brief Construct a NegativeUNL ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit NegativeUNL(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for NegativeUNL"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfDisabledValidators (soeOPTIONAL) + * @note This is an untyped field (unknown). + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getDisabledValidators() const + { + if (this->sle_->isFieldPresent(sfDisabledValidators)) + return this->sle_->getFieldArray(sfDisabledValidators); + return std::nullopt; + } + + /** + * @brief Check if sfDisabledValidators is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDisabledValidators() const + { + return this->sle_->isFieldPresent(sfDisabledValidators); + } + + /** + * @brief Get sfValidatorToDisable (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getValidatorToDisable() const + { + if (hasValidatorToDisable()) + return this->sle_->at(sfValidatorToDisable); + return std::nullopt; + } + + /** + * @brief Check if sfValidatorToDisable is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasValidatorToDisable() const + { + return this->sle_->isFieldPresent(sfValidatorToDisable); + } + + /** + * @brief Get sfValidatorToReEnable (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getValidatorToReEnable() const + { + if (hasValidatorToReEnable()) + return this->sle_->at(sfValidatorToReEnable); + return std::nullopt; + } + + /** + * @brief Check if sfValidatorToReEnable is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasValidatorToReEnable() const + { + return this->sle_->isFieldPresent(sfValidatorToReEnable); + } + + /** + * @brief Get sfPreviousTxnID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnID() const + { + if (hasPreviousTxnID()) + return this->sle_->at(sfPreviousTxnID); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnID() const + { + return this->sle_->isFieldPresent(sfPreviousTxnID); + } + + /** + * @brief Get sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPreviousTxnLgrSeq() const + { + if (hasPreviousTxnLgrSeq()) + return this->sle_->at(sfPreviousTxnLgrSeq); + return std::nullopt; + } + + /** + * @brief Check if sfPreviousTxnLgrSeq is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPreviousTxnLgrSeq() const + { + return this->sle_->isFieldPresent(sfPreviousTxnLgrSeq); + } +}; + +/** + * @brief Builder for NegativeUNL ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class NegativeUNLBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new NegativeUNLBuilder with required fields. + */ + NegativeUNLBuilder() + : LedgerEntryBuilderBase(ltNEGATIVE_UNL) + { + } + + /** + * @brief Construct a NegativeUNLBuilder 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. + */ + NegativeUNLBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltNEGATIVE_UNL) + { + throw std::runtime_error("Invalid ledger entry type for NegativeUNL"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfDisabledValidators (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NegativeUNLBuilder& + setDisabledValidators(STArray const& value) + { + object_.setFieldArray(sfDisabledValidators, value); + return *this; + } + + /** + * @brief Set sfValidatorToDisable (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NegativeUNLBuilder& + setValidatorToDisable(std::decay_t const& value) + { + object_[sfValidatorToDisable] = value; + return *this; + } + + /** + * @brief Set sfValidatorToReEnable (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NegativeUNLBuilder& + setValidatorToReEnable(std::decay_t const& value) + { + object_[sfValidatorToReEnable] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NegativeUNLBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NegativeUNLBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed NegativeUNL wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + NegativeUNL + build(uint256 const& index) + { + return NegativeUNL{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Offer.h b/include/xrpl/protocol_autogen/ledger_entries/Offer.h new file mode 100644 index 0000000000..cccd9183a1 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Offer.h @@ -0,0 +1,417 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class OfferBuilder; + +/** + * @brief Ledger Entry: Offer + * + * Type: ltOFFER (0x006f) + * RPC Name: offer + * + * Immutable wrapper around SLE providing type-safe field access. + * Use OfferBuilder to construct new ledger entries. + */ +class Offer : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltOFFER; + + /** + * @brief Construct a Offer ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Offer(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Offer"); + } + } + + // 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 sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfTakerPays (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getTakerPays() const + { + return this->sle_->at(sfTakerPays); + } + + /** + * @brief Get sfTakerGets (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getTakerGets() const + { + return this->sle_->at(sfTakerGets); + } + + /** + * @brief Get sfBookDirectory (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getBookDirectory() const + { + return this->sle_->at(sfBookDirectory); + } + + /** + * @brief Get sfBookNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getBookNode() const + { + return this->sle_->at(sfBookNode); + } + + /** + * @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 Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + return this->sle_->at(sfExpiration); + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->sle_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + return this->sle_->at(sfDomainID); + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->sle_->isFieldPresent(sfDomainID); + } + + /** + * @brief Get sfAdditionalBooks (soeOPTIONAL) + * @note This is an untyped field (unknown). + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getAdditionalBooks() const + { + if (this->sle_->isFieldPresent(sfAdditionalBooks)) + return this->sle_->getFieldArray(sfAdditionalBooks); + return std::nullopt; + } + + /** + * @brief Check if sfAdditionalBooks is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAdditionalBooks() const + { + return this->sle_->isFieldPresent(sfAdditionalBooks); + } +}; + +/** + * @brief Builder for Offer ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class OfferBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new OfferBuilder with required fields. + * @param account The sfAccount field value. + * @param sequence The sfSequence field value. + * @param takerPays The sfTakerPays field value. + * @param takerGets The sfTakerGets field value. + * @param bookDirectory The sfBookDirectory field value. + * @param bookNode The sfBookNode field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + OfferBuilder(std::decay_t const& account,std::decay_t const& sequence,std::decay_t const& takerPays,std::decay_t const& takerGets,std::decay_t const& bookDirectory,std::decay_t const& bookNode,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltOFFER) + { + setAccount(account); + setSequence(sequence); + setTakerPays(takerPays); + setTakerGets(takerGets); + setBookDirectory(bookDirectory); + setBookNode(bookNode); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a OfferBuilder 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. + */ + OfferBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltOFFER) + { + throw std::runtime_error("Invalid ledger entry type for Offer"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfTakerPays (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setTakerPays(std::decay_t const& value) + { + object_[sfTakerPays] = value; + return *this; + } + + /** + * @brief Set sfTakerGets (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setTakerGets(std::decay_t const& value) + { + object_[sfTakerGets] = value; + return *this; + } + + /** + * @brief Set sfBookDirectory (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setBookDirectory(std::decay_t const& value) + { + object_[sfBookDirectory] = value; + return *this; + } + + /** + * @brief Set sfBookNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setBookNode(std::decay_t const& value) + { + object_[sfBookNode] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfAdditionalBooks (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OfferBuilder& + setAdditionalBooks(STArray const& value) + { + object_.setFieldArray(sfAdditionalBooks, value); + return *this; + } + + /** + * @brief Build and return the completed Offer wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Offer + build(uint256 const& index) + { + return Offer{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Oracle.h b/include/xrpl/protocol_autogen/ledger_entries/Oracle.h new file mode 100644 index 0000000000..4da93773e6 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Oracle.h @@ -0,0 +1,358 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class OracleBuilder; + +/** + * @brief Ledger Entry: Oracle + * + * Type: ltORACLE (0x0080) + * RPC Name: oracle + * + * Immutable wrapper around SLE providing type-safe field access. + * Use OracleBuilder to construct new ledger entries. + */ +class Oracle : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltORACLE; + + /** + * @brief Construct a Oracle ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Oracle(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Oracle"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->sle_->at(sfOwner); + } + + /** + * @brief Get sfOracleDocumentID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOracleDocumentID() const + { + if (hasOracleDocumentID()) + return this->sle_->at(sfOracleDocumentID); + return std::nullopt; + } + + /** + * @brief Check if sfOracleDocumentID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOracleDocumentID() const + { + return this->sle_->isFieldPresent(sfOracleDocumentID); + } + + /** + * @brief Get sfProvider (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getProvider() const + { + return this->sle_->at(sfProvider); + } + + /** + * @brief Get sfPriceDataSeries (soeREQUIRED) + * @note This is an untyped field (unknown). + * @return The field value. + */ + [[nodiscard]] + STArray const& + getPriceDataSeries() const + { + return this->sle_->getFieldArray(sfPriceDataSeries); + } + + /** + * @brief Get sfAssetClass (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getAssetClass() const + { + return this->sle_->at(sfAssetClass); + } + + /** + * @brief Get sfLastUpdateTime (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getLastUpdateTime() const + { + return this->sle_->at(sfLastUpdateTime); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + return this->sle_->at(sfURI); + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->sle_->isFieldPresent(sfURI); + } + + /** + * @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 Oracle ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class OracleBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new OracleBuilder with required fields. + * @param owner The sfOwner field value. + * @param provider The sfProvider field value. + * @param priceDataSeries The sfPriceDataSeries field value. + * @param assetClass The sfAssetClass field value. + * @param lastUpdateTime The sfLastUpdateTime field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + OracleBuilder(std::decay_t const& owner,std::decay_t const& provider,STArray const& priceDataSeries,std::decay_t const& assetClass,std::decay_t const& lastUpdateTime,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltORACLE) + { + setOwner(owner); + setProvider(provider); + setPriceDataSeries(priceDataSeries); + setAssetClass(assetClass); + setLastUpdateTime(lastUpdateTime); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a OracleBuilder 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. + */ + OracleBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltORACLE) + { + throw std::runtime_error("Invalid ledger entry type for Oracle"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfOracleDocumentID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setOracleDocumentID(std::decay_t const& value) + { + object_[sfOracleDocumentID] = value; + return *this; + } + + /** + * @brief Set sfProvider (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setProvider(std::decay_t const& value) + { + object_[sfProvider] = value; + return *this; + } + + /** + * @brief Set sfPriceDataSeries (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setPriceDataSeries(STArray const& value) + { + object_.setFieldArray(sfPriceDataSeries, value); + return *this; + } + + /** + * @brief Set sfAssetClass (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setAssetClass(std::decay_t const& value) + { + object_[sfAssetClass] = value; + return *this; + } + + /** + * @brief Set sfLastUpdateTime (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setLastUpdateTime(std::decay_t const& value) + { + object_[sfLastUpdateTime] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed Oracle wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Oracle + build(uint256 const& index) + { + return Oracle{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/PayChannel.h b/include/xrpl/protocol_autogen/ledger_entries/PayChannel.h new file mode 100644 index 0000000000..50245bc0d8 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/PayChannel.h @@ -0,0 +1,521 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class PayChannelBuilder; + +/** + * @brief Ledger Entry: PayChannel + * + * Type: ltPAYCHAN (0x0078) + * RPC Name: payment_channel + * + * Immutable wrapper around SLE providing type-safe field access. + * Use PayChannelBuilder to construct new ledger entries. + */ +class PayChannel : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltPAYCHAN; + + /** + * @brief Construct a PayChannel ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit PayChannel(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for PayChannel"); + } + } + + // 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 sfDestination (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getDestination() const + { + return this->sle_->at(sfDestination); + } + + /** + * @brief Get sfSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSequence() const + { + if (hasSequence()) + return this->sle_->at(sfSequence); + return std::nullopt; + } + + /** + * @brief Check if sfSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSequence() const + { + return this->sle_->isFieldPresent(sfSequence); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->sle_->at(sfAmount); + } + + /** + * @brief Get sfBalance (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getBalance() const + { + return this->sle_->at(sfBalance); + } + + /** + * @brief Get sfPublicKey (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getPublicKey() const + { + return this->sle_->at(sfPublicKey); + } + + /** + * @brief Get sfSettleDelay (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSettleDelay() const + { + return this->sle_->at(sfSettleDelay); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + return this->sle_->at(sfExpiration); + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->sle_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfCancelAfter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCancelAfter() const + { + if (hasCancelAfter()) + return this->sle_->at(sfCancelAfter); + return std::nullopt; + } + + /** + * @brief Check if sfCancelAfter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCancelAfter() const + { + return this->sle_->isFieldPresent(sfCancelAfter); + } + + /** + * @brief Get sfSourceTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSourceTag() const + { + if (hasSourceTag()) + return this->sle_->at(sfSourceTag); + return std::nullopt; + } + + /** + * @brief Check if sfSourceTag is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSourceTag() const + { + return this->sle_->isFieldPresent(sfSourceTag); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDestinationTag() const + { + if (hasDestinationTag()) + return this->sle_->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->sle_->isFieldPresent(sfDestinationTag); + } + + /** + * @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 Get sfDestinationNode (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDestinationNode() const + { + if (hasDestinationNode()) + return this->sle_->at(sfDestinationNode); + return std::nullopt; + } + + /** + * @brief Check if sfDestinationNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDestinationNode() const + { + return this->sle_->isFieldPresent(sfDestinationNode); + } +}; + +/** + * @brief Builder for PayChannel ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class PayChannelBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new PayChannelBuilder with required fields. + * @param account The sfAccount field value. + * @param destination The sfDestination field value. + * @param amount The sfAmount field value. + * @param balance The sfBalance field value. + * @param publicKey The sfPublicKey field value. + * @param settleDelay The sfSettleDelay field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + PayChannelBuilder(std::decay_t const& account,std::decay_t const& destination,std::decay_t const& amount,std::decay_t const& balance,std::decay_t const& publicKey,std::decay_t const& settleDelay,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltPAYCHAN) + { + setAccount(account); + setDestination(destination); + setAmount(amount); + setBalance(balance); + setPublicKey(publicKey); + setSettleDelay(settleDelay); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a PayChannelBuilder 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. + */ + PayChannelBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltPAYCHAN) + { + throw std::runtime_error("Invalid ledger entry type for PayChannel"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfBalance (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setBalance(std::decay_t const& value) + { + object_[sfBalance] = value; + return *this; + } + + /** + * @brief Set sfPublicKey (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setPublicKey(std::decay_t const& value) + { + object_[sfPublicKey] = value; + return *this; + } + + /** + * @brief Set sfSettleDelay (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setSettleDelay(std::decay_t const& value) + { + object_[sfSettleDelay] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfCancelAfter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setCancelAfter(std::decay_t const& value) + { + object_[sfCancelAfter] = value; + return *this; + } + + /** + * @brief Set sfSourceTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setSourceTag(std::decay_t const& value) + { + object_[sfSourceTag] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfDestinationNode (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PayChannelBuilder& + setDestinationNode(std::decay_t const& value) + { + object_[sfDestinationNode] = value; + return *this; + } + + /** + * @brief Build and return the completed PayChannel wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + PayChannel + build(uint256 const& index) + { + return PayChannel{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/PermissionedDomain.h b/include/xrpl/protocol_autogen/ledger_entries/PermissionedDomain.h new file mode 100644 index 0000000000..630f46517f --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/PermissionedDomain.h @@ -0,0 +1,240 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class PermissionedDomainBuilder; + +/** + * @brief Ledger Entry: PermissionedDomain + * + * Type: ltPERMISSIONED_DOMAIN (0x0082) + * RPC Name: permissioned_domain + * + * Immutable wrapper around SLE providing type-safe field access. + * Use PermissionedDomainBuilder to construct new ledger entries. + */ +class PermissionedDomain : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltPERMISSIONED_DOMAIN; + + /** + * @brief Construct a PermissionedDomain ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit PermissionedDomain(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for PermissionedDomain"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->sle_->at(sfOwner); + } + + /** + * @brief Get sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfAcceptedCredentials (soeREQUIRED) + * @note This is an untyped field (unknown). + * @return The field value. + */ + [[nodiscard]] + STArray const& + getAcceptedCredentials() const + { + return this->sle_->getFieldArray(sfAcceptedCredentials); + } + + /** + * @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 PermissionedDomain ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class PermissionedDomainBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new PermissionedDomainBuilder with required fields. + * @param owner The sfOwner field value. + * @param sequence The sfSequence field value. + * @param acceptedCredentials The sfAcceptedCredentials field value. + * @param ownerNode The sfOwnerNode field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + PermissionedDomainBuilder(std::decay_t const& owner,std::decay_t const& sequence,STArray const& acceptedCredentials,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltPERMISSIONED_DOMAIN) + { + setOwner(owner); + setSequence(sequence); + setAcceptedCredentials(acceptedCredentials); + setOwnerNode(ownerNode); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a PermissionedDomainBuilder 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. + */ + PermissionedDomainBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltPERMISSIONED_DOMAIN) + { + throw std::runtime_error("Invalid ledger entry type for PermissionedDomain"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfAcceptedCredentials (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainBuilder& + setAcceptedCredentials(STArray const& value) + { + object_.setFieldArray(sfAcceptedCredentials, value); + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed PermissionedDomain wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + PermissionedDomain + build(uint256 const& index) + { + return PermissionedDomain{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/RippleState.h b/include/xrpl/protocol_autogen/ledger_entries/RippleState.h new file mode 100644 index 0000000000..993496d38f --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/RippleState.h @@ -0,0 +1,425 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class RippleStateBuilder; + +/** + * @brief Ledger Entry: RippleState + * + * Type: ltRIPPLE_STATE (0x0072) + * RPC Name: state + * + * Immutable wrapper around SLE providing type-safe field access. + * Use RippleStateBuilder to construct new ledger entries. + */ +class RippleState : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltRIPPLE_STATE; + + /** + * @brief Construct a RippleState ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit RippleState(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for RippleState"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfBalance (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getBalance() const + { + return this->sle_->at(sfBalance); + } + + /** + * @brief Get sfLowLimit (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getLowLimit() const + { + return this->sle_->at(sfLowLimit); + } + + /** + * @brief Get sfHighLimit (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getHighLimit() const + { + return this->sle_->at(sfHighLimit); + } + + /** + * @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 sfLowNode (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLowNode() const + { + if (hasLowNode()) + return this->sle_->at(sfLowNode); + return std::nullopt; + } + + /** + * @brief Check if sfLowNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLowNode() const + { + return this->sle_->isFieldPresent(sfLowNode); + } + + /** + * @brief Get sfLowQualityIn (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLowQualityIn() const + { + if (hasLowQualityIn()) + return this->sle_->at(sfLowQualityIn); + return std::nullopt; + } + + /** + * @brief Check if sfLowQualityIn is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLowQualityIn() const + { + return this->sle_->isFieldPresent(sfLowQualityIn); + } + + /** + * @brief Get sfLowQualityOut (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLowQualityOut() const + { + if (hasLowQualityOut()) + return this->sle_->at(sfLowQualityOut); + return std::nullopt; + } + + /** + * @brief Check if sfLowQualityOut is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLowQualityOut() const + { + return this->sle_->isFieldPresent(sfLowQualityOut); + } + + /** + * @brief Get sfHighNode (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getHighNode() const + { + if (hasHighNode()) + return this->sle_->at(sfHighNode); + return std::nullopt; + } + + /** + * @brief Check if sfHighNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasHighNode() const + { + return this->sle_->isFieldPresent(sfHighNode); + } + + /** + * @brief Get sfHighQualityIn (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getHighQualityIn() const + { + if (hasHighQualityIn()) + return this->sle_->at(sfHighQualityIn); + return std::nullopt; + } + + /** + * @brief Check if sfHighQualityIn is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasHighQualityIn() const + { + return this->sle_->isFieldPresent(sfHighQualityIn); + } + + /** + * @brief Get sfHighQualityOut (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getHighQualityOut() const + { + if (hasHighQualityOut()) + return this->sle_->at(sfHighQualityOut); + return std::nullopt; + } + + /** + * @brief Check if sfHighQualityOut is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasHighQualityOut() const + { + return this->sle_->isFieldPresent(sfHighQualityOut); + } +}; + +/** + * @brief Builder for RippleState ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class RippleStateBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new RippleStateBuilder with required fields. + * @param balance The sfBalance field value. + * @param lowLimit The sfLowLimit field value. + * @param highLimit The sfHighLimit field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + RippleStateBuilder(std::decay_t const& balance,std::decay_t const& lowLimit,std::decay_t const& highLimit,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltRIPPLE_STATE) + { + setBalance(balance); + setLowLimit(lowLimit); + setHighLimit(highLimit); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a RippleStateBuilder 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. + */ + RippleStateBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltRIPPLE_STATE) + { + throw std::runtime_error("Invalid ledger entry type for RippleState"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfBalance (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setBalance(std::decay_t const& value) + { + object_[sfBalance] = value; + return *this; + } + + /** + * @brief Set sfLowLimit (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setLowLimit(std::decay_t const& value) + { + object_[sfLowLimit] = value; + return *this; + } + + /** + * @brief Set sfHighLimit (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setHighLimit(std::decay_t const& value) + { + object_[sfHighLimit] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfLowNode (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setLowNode(std::decay_t const& value) + { + object_[sfLowNode] = value; + return *this; + } + + /** + * @brief Set sfLowQualityIn (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setLowQualityIn(std::decay_t const& value) + { + object_[sfLowQualityIn] = value; + return *this; + } + + /** + * @brief Set sfLowQualityOut (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setLowQualityOut(std::decay_t const& value) + { + object_[sfLowQualityOut] = value; + return *this; + } + + /** + * @brief Set sfHighNode (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setHighNode(std::decay_t const& value) + { + object_[sfHighNode] = value; + return *this; + } + + /** + * @brief Set sfHighQualityIn (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setHighQualityIn(std::decay_t const& value) + { + object_[sfHighQualityIn] = value; + return *this; + } + + /** + * @brief Set sfHighQualityOut (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + RippleStateBuilder& + setHighQualityOut(std::decay_t const& value) + { + object_[sfHighQualityOut] = value; + return *this; + } + + /** + * @brief Build and return the completed RippleState wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + RippleState + build(uint256 const& index) + { + return RippleState{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/SignerList.h b/include/xrpl/protocol_autogen/ledger_entries/SignerList.h new file mode 100644 index 0000000000..57d706bc28 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/SignerList.h @@ -0,0 +1,275 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class SignerListBuilder; + +/** + * @brief Ledger Entry: SignerList + * + * Type: ltSIGNER_LIST (0x0053) + * RPC Name: signer_list + * + * Immutable wrapper around SLE providing type-safe field access. + * Use SignerListBuilder to construct new ledger entries. + */ +class SignerList : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltSIGNER_LIST; + + /** + * @brief Construct a SignerList ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit SignerList(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for SignerList"); + } + } + + // Ledger entry-specific field getters + + /** + * @brief Get sfOwner (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwner() const + { + if (hasOwner()) + return this->sle_->at(sfOwner); + return std::nullopt; + } + + /** + * @brief Check if sfOwner is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwner() const + { + return this->sle_->isFieldPresent(sfOwner); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfSignerQuorum (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSignerQuorum() const + { + return this->sle_->at(sfSignerQuorum); + } + + /** + * @brief Get sfSignerEntries (soeREQUIRED) + * @note This is an untyped field (unknown). + * @return The field value. + */ + [[nodiscard]] + STArray const& + getSignerEntries() const + { + return this->sle_->getFieldArray(sfSignerEntries); + } + + /** + * @brief Get sfSignerListID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSignerListID() const + { + return this->sle_->at(sfSignerListID); + } + + /** + * @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 SignerList ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class SignerListBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new SignerListBuilder with required fields. + * @param ownerNode The sfOwnerNode field value. + * @param signerQuorum The sfSignerQuorum field value. + * @param signerEntries The sfSignerEntries field value. + * @param signerListID The sfSignerListID field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + SignerListBuilder(std::decay_t const& ownerNode,std::decay_t const& signerQuorum,STArray const& signerEntries,std::decay_t const& signerListID,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltSIGNER_LIST) + { + setOwnerNode(ownerNode); + setSignerQuorum(signerQuorum); + setSignerEntries(signerEntries); + setSignerListID(signerListID); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a SignerListBuilder 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. + */ + SignerListBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltSIGNER_LIST) + { + throw std::runtime_error("Invalid ledger entry type for SignerList"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfOwner (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfSignerQuorum (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setSignerQuorum(std::decay_t const& value) + { + object_[sfSignerQuorum] = value; + return *this; + } + + /** + * @brief Set sfSignerEntries (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setSignerEntries(STArray const& value) + { + object_.setFieldArray(sfSignerEntries, value); + return *this; + } + + /** + * @brief Set sfSignerListID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setSignerListID(std::decay_t const& value) + { + object_[sfSignerListID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed SignerList wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + SignerList + build(uint256 const& index) + { + return SignerList{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Ticket.h b/include/xrpl/protocol_autogen/ledger_entries/Ticket.h new file mode 100644 index 0000000000..f13e8a398f --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Ticket.h @@ -0,0 +1,215 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class TicketBuilder; + +/** + * @brief Ledger Entry: Ticket + * + * Type: ltTICKET (0x0054) + * RPC Name: ticket + * + * Immutable wrapper around SLE providing type-safe field access. + * Use TicketBuilder to construct new ledger entries. + */ +class Ticket : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltTICKET; + + /** + * @brief Construct a Ticket ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Ticket(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Ticket"); + } + } + + // 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 sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfTicketSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getTicketSequence() const + { + return this->sle_->at(sfTicketSequence); + } + + /** + * @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 Ticket ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class TicketBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new TicketBuilder with required fields. + * @param account The sfAccount field value. + * @param ownerNode The sfOwnerNode field value. + * @param ticketSequence The sfTicketSequence field value. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + */ + TicketBuilder(std::decay_t const& account,std::decay_t const& ownerNode,std::decay_t const& ticketSequence,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(ltTICKET) + { + setAccount(account); + setOwnerNode(ownerNode); + setTicketSequence(ticketSequence); + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + } + + /** + * @brief Construct a TicketBuilder 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. + */ + TicketBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltTICKET) + { + throw std::runtime_error("Invalid ledger entry type for Ticket"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + TicketBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + TicketBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfTicketSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + TicketBuilder& + setTicketSequence(std::decay_t const& value) + { + object_[sfTicketSequence] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + TicketBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + TicketBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Build and return the completed Ticket wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Ticket + build(uint256 const& index) + { + return Ticket{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/Vault.h b/include/xrpl/protocol_autogen/ledger_entries/Vault.h new file mode 100644 index 0000000000..e24e73fab3 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/Vault.h @@ -0,0 +1,521 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class VaultBuilder; + +/** + * @brief Ledger Entry: Vault + * + * Type: ltVAULT (0x0084) + * RPC Name: vault + * + * Immutable wrapper around SLE providing type-safe field access. + * Use VaultBuilder to construct new ledger entries. + */ +class Vault : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ltVAULT; + + /** + * @brief Construct a Vault ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit Vault(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for Vault"); + } + } + + // 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 sfSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSequence() const + { + return this->sle_->at(sfSequence); + } + + /** + * @brief Get sfOwnerNode (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT64::type::value_type + getOwnerNode() const + { + return this->sle_->at(sfOwnerNode); + } + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->sle_->at(sfOwner); + } + + /** + * @brief Get sfAccount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getAccount() const + { + return this->sle_->at(sfAccount); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + return this->sle_->at(sfData); + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->sle_->isFieldPresent(sfData); + } + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->sle_->at(sfAsset); + } + + /** + * @brief Get sfAssetsTotal (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetsTotal() const + { + if (hasAssetsTotal()) + return this->sle_->at(sfAssetsTotal); + return std::nullopt; + } + + /** + * @brief Check if sfAssetsTotal is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetsTotal() const + { + return this->sle_->isFieldPresent(sfAssetsTotal); + } + + /** + * @brief Get sfAssetsAvailable (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetsAvailable() const + { + if (hasAssetsAvailable()) + return this->sle_->at(sfAssetsAvailable); + return std::nullopt; + } + + /** + * @brief Check if sfAssetsAvailable is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetsAvailable() const + { + return this->sle_->isFieldPresent(sfAssetsAvailable); + } + + /** + * @brief Get sfAssetsMaximum (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetsMaximum() const + { + if (hasAssetsMaximum()) + return this->sle_->at(sfAssetsMaximum); + return std::nullopt; + } + + /** + * @brief Check if sfAssetsMaximum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetsMaximum() const + { + return this->sle_->isFieldPresent(sfAssetsMaximum); + } + + /** + * @brief Get sfLossUnrealized (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLossUnrealized() const + { + if (hasLossUnrealized()) + return this->sle_->at(sfLossUnrealized); + return std::nullopt; + } + + /** + * @brief Check if sfLossUnrealized is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLossUnrealized() const + { + return this->sle_->isFieldPresent(sfLossUnrealized); + } + + /** + * @brief Get sfShareMPTID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT192::type::value_type + getShareMPTID() const + { + return this->sle_->at(sfShareMPTID); + } + + /** + * @brief Get sfWithdrawalPolicy (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT8::type::value_type + getWithdrawalPolicy() const + { + return this->sle_->at(sfWithdrawalPolicy); + } + + /** + * @brief Get sfScale (soeDEFAULT) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getScale() const + { + if (hasScale()) + return this->sle_->at(sfScale); + return std::nullopt; + } + + /** + * @brief Check if sfScale is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasScale() const + { + return this->sle_->isFieldPresent(sfScale); + } +}; + +/** + * @brief Builder for Vault ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class VaultBuilder : public LedgerEntryBuilderBase +{ +public: + /** + * @brief Construct a new VaultBuilder with required fields. + * @param previousTxnID The sfPreviousTxnID field value. + * @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value. + * @param sequence The sfSequence field value. + * @param ownerNode The sfOwnerNode field value. + * @param owner The sfOwner field value. + * @param account The sfAccount field value. + * @param asset The sfAsset field value. + * @param shareMPTID The sfShareMPTID field value. + * @param withdrawalPolicy The sfWithdrawalPolicy field value. + */ + VaultBuilder(std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq,std::decay_t const& sequence,std::decay_t const& ownerNode,std::decay_t const& owner,std::decay_t const& account,std::decay_t const& asset,std::decay_t const& shareMPTID,std::decay_t const& withdrawalPolicy) + : LedgerEntryBuilderBase(ltVAULT) + { + setPreviousTxnID(previousTxnID); + setPreviousTxnLgrSeq(previousTxnLgrSeq); + setSequence(sequence); + setOwnerNode(ownerNode); + setOwner(owner); + setAccount(account); + setAsset(asset); + setShareMPTID(shareMPTID); + setWithdrawalPolicy(withdrawalPolicy); + } + + /** + * @brief Construct a VaultBuilder 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. + */ + VaultBuilder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ltVAULT) + { + throw std::runtime_error("Invalid ledger entry type for Vault"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setPreviousTxnLgrSeq(std::decay_t const& value) + { + object_[sfPreviousTxnLgrSeq] = value; + return *this; + } + + /** + * @brief Set sfSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setSequence(std::decay_t const& value) + { + object_[sfSequence] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setAccount(std::decay_t const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAssetsTotal (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setAssetsTotal(std::decay_t const& value) + { + object_[sfAssetsTotal] = value; + return *this; + } + + /** + * @brief Set sfAssetsAvailable (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setAssetsAvailable(std::decay_t const& value) + { + object_[sfAssetsAvailable] = value; + return *this; + } + + /** + * @brief Set sfAssetsMaximum (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setAssetsMaximum(std::decay_t const& value) + { + object_[sfAssetsMaximum] = value; + return *this; + } + + /** + * @brief Set sfLossUnrealized (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setLossUnrealized(std::decay_t const& value) + { + object_[sfLossUnrealized] = value; + return *this; + } + + /** + * @brief Set sfShareMPTID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setShareMPTID(std::decay_t const& value) + { + object_[sfShareMPTID] = value; + return *this; + } + + /** + * @brief Set sfWithdrawalPolicy (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setWithdrawalPolicy(std::decay_t const& value) + { + object_[sfWithdrawalPolicy] = value; + return *this; + } + + /** + * @brief Set sfScale (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setScale(std::decay_t const& value) + { + object_[sfScale] = value; + return *this; + } + + /** + * @brief Build and return the completed Vault wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + Vault + build(uint256 const& index) + { + return Vault{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h b/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h new file mode 100644 index 0000000000..3309228951 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedClaimID.h @@ -0,0 +1,312 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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(std::shared_ptr 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 Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class XChainOwnedClaimIDBuilder : public LedgerEntryBuilderBase +{ +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 const& account,std::decay_t const& xChainBridge,std::decay_t const& xChainClaimID,std::decay_t const& otherChainSource,STArray const& xChainClaimAttestations,std::decay_t const& signatureReward,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(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(std::shared_ptr 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 const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfXChainBridge (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedClaimIDBuilder& + setXChainBridge(std::decay_t const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfXChainClaimID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedClaimIDBuilder& + setXChainClaimID(std::decay_t const& value) + { + object_[sfXChainClaimID] = value; + return *this; + } + + /** + * @brief Set sfOtherChainSource (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedClaimIDBuilder& + setOtherChainSource(std::decay_t 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 const& value) + { + object_[sfSignatureReward] = value; + return *this; + } + + /** + * @brief Set sfOwnerNode (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedClaimIDBuilder& + setOwnerNode(std::decay_t const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedClaimIDBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedClaimIDBuilder& + setPreviousTxnLgrSeq(std::decay_t 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(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h b/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h new file mode 100644 index 0000000000..5415d52884 --- /dev/null +++ b/include/xrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimID.h @@ -0,0 +1,264 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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(std::shared_ptr 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 Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class XChainOwnedCreateAccountClaimIDBuilder : public LedgerEntryBuilderBase +{ +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 const& account,std::decay_t const& xChainBridge,std::decay_t const& xChainAccountCreateCount,STArray const& xChainCreateAccountAttestations,std::decay_t const& ownerNode,std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq) + : LedgerEntryBuilderBase(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(std::shared_ptr 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 const& value) + { + object_[sfAccount] = value; + return *this; + } + + /** + * @brief Set sfXChainBridge (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedCreateAccountClaimIDBuilder& + setXChainBridge(std::decay_t const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfXChainAccountCreateCount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedCreateAccountClaimIDBuilder& + setXChainAccountCreateCount(std::decay_t 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 const& value) + { + object_[sfOwnerNode] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedCreateAccountClaimIDBuilder& + setPreviousTxnID(std::decay_t const& value) + { + object_[sfPreviousTxnID] = value; + return *this; + } + + /** + * @brief Set sfPreviousTxnLgrSeq (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainOwnedCreateAccountClaimIDBuilder& + setPreviousTxnLgrSeq(std::decay_t 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(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/include/xrpl/protocol_autogen/transactions/AMMBid.h b/include/xrpl/protocol_autogen/transactions/AMMBid.h new file mode 100644 index 0000000000..d3f8cba8f7 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMBid.h @@ -0,0 +1,262 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMBidBuilder; + +/** + * @brief Transaction: AMMBid + * + * Type: ttAMM_BID (39) + * Delegable: Delegation::delegable + * Amendment: featureAMM + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMBidBuilder to construct new transactions. + */ +class AMMBid : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_BID; + + /** + * @brief Construct a AMMBid transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMBid(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMBid"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->tx_->at(sfAsset2); + } + + /** + * @brief Get sfBidMin (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBidMin() const + { + if (hasBidMin()) + { + return this->tx_->at(sfBidMin); + } + return std::nullopt; + } + + /** + * @brief Check if sfBidMin is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBidMin() const + { + return this->tx_->isFieldPresent(sfBidMin); + } + + /** + * @brief Get sfBidMax (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBidMax() const + { + if (hasBidMax()) + { + return this->tx_->at(sfBidMax); + } + return std::nullopt; + } + + /** + * @brief Check if sfBidMax is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBidMax() const + { + return this->tx_->isFieldPresent(sfBidMax); + } + /** + * @brief Get sfAuthAccounts (soeOPTIONAL) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getAuthAccounts() const + { + if (this->tx_->isFieldPresent(sfAuthAccounts)) + return this->tx_->getFieldArray(sfAuthAccounts); + return std::nullopt; + } + + /** + * @brief Check if sfAuthAccounts is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAuthAccounts() const + { + return this->tx_->isFieldPresent(sfAuthAccounts); + } +}; + +/** + * @brief Builder for AMMBid transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMBidBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMBidBuilder with required fields. + * @param account The account initiating the transaction. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMBidBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& asset, std::decay_t const& asset2, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_BID, account, sequence, fee) + { + setAsset(asset); + setAsset2(asset2); + } + + /** + * @brief Construct a AMMBidBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMBidBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_BID) + { + throw std::runtime_error("Invalid transaction type for AMMBidBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBidBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMBidBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Set sfBidMin (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBidBuilder& + setBidMin(std::decay_t const& value) + { + object_[sfBidMin] = value; + return *this; + } + + /** + * @brief Set sfBidMax (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBidBuilder& + setBidMax(std::decay_t const& value) + { + object_[sfBidMax] = value; + return *this; + } + + /** + * @brief Set sfAuthAccounts (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMBidBuilder& + setAuthAccounts(STArray const& value) + { + object_.setFieldArray(sfAuthAccounts, value); + return *this; + } + + /** + * @brief Build and return the AMMBid wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMBid + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMBid{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AMMClawback.h b/include/xrpl/protocol_autogen/transactions/AMMClawback.h new file mode 100644 index 0000000000..9603cad6ef --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMClawback.h @@ -0,0 +1,214 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMClawbackBuilder; + +/** + * @brief Transaction: AMMClawback + * + * Type: ttAMM_CLAWBACK (31) + * Delegable: Delegation::delegable + * Amendment: featureAMMClawback + * Privileges: mayDeleteAcct | overrideFreeze + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMClawbackBuilder to construct new transactions. + */ +class AMMClawback : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_CLAWBACK; + + /** + * @brief Construct a AMMClawback transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMClawback(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMClawback"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfHolder (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getHolder() const + { + return this->tx_->at(sfHolder); + } + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->tx_->at(sfAsset2); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } +}; + +/** + * @brief Builder for AMMClawback transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMClawbackBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMClawbackBuilder with required fields. + * @param account The account initiating the transaction. + * @param holder The sfHolder field value. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMClawbackBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& holder, std::decay_t const& asset, std::decay_t const& asset2, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_CLAWBACK, account, sequence, fee) + { + setHolder(holder); + setAsset(asset); + setAsset2(asset2); + } + + /** + * @brief Construct a AMMClawbackBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMClawbackBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_CLAWBACK) + { + throw std::runtime_error("Invalid transaction type for AMMClawbackBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfHolder (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMClawbackBuilder& + setHolder(std::decay_t const& value) + { + object_[sfHolder] = value; + return *this; + } + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMClawbackBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMClawbackBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMClawbackBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Build and return the AMMClawback wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMClawback + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMClawback{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AMMCreate.h b/include/xrpl/protocol_autogen/transactions/AMMCreate.h new file mode 100644 index 0000000000..311d19a3c4 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMCreate.h @@ -0,0 +1,177 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMCreateBuilder; + +/** + * @brief Transaction: AMMCreate + * + * Type: ttAMM_CREATE (35) + * Delegable: Delegation::delegable + * Amendment: featureAMM + * Privileges: createPseudoAcct + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMCreateBuilder to construct new transactions. + */ +class AMMCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_CREATE; + + /** + * @brief Construct a AMMCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfAmount2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount2() const + { + return this->tx_->at(sfAmount2); + } + + /** + * @brief Get sfTradingFee (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT16::type::value_type + getTradingFee() const + { + return this->tx_->at(sfTradingFee); + } +}; + +/** + * @brief Builder for AMMCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param amount The sfAmount field value. + * @param amount2 The sfAmount2 field value. + * @param tradingFee The sfTradingFee field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& amount, std::decay_t const& amount2, std::decay_t const& tradingFee, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_CREATE, account, sequence, fee) + { + setAmount(amount); + setAmount2(amount2); + setTradingFee(tradingFee); + } + + /** + * @brief Construct a AMMCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_CREATE) + { + throw std::runtime_error("Invalid transaction type for AMMCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMCreateBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfAmount2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMCreateBuilder& + setAmount2(std::decay_t const& value) + { + object_[sfAmount2] = value; + return *this; + } + + /** + * @brief Set sfTradingFee (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMCreateBuilder& + setTradingFee(std::decay_t const& value) + { + object_[sfTradingFee] = value; + return *this; + } + + /** + * @brief Build and return the AMMCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AMMDelete.h b/include/xrpl/protocol_autogen/transactions/AMMDelete.h new file mode 100644 index 0000000000..bc61434d0b --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMDelete.h @@ -0,0 +1,153 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMDeleteBuilder; + +/** + * @brief Transaction: AMMDelete + * + * Type: ttAMM_DELETE (40) + * Delegable: Delegation::delegable + * Amendment: featureAMM + * Privileges: mustDeleteAcct + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMDeleteBuilder to construct new transactions. + */ +class AMMDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_DELETE; + + /** + * @brief Construct a AMMDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->tx_->at(sfAsset2); + } +}; + +/** + * @brief Builder for AMMDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& asset, std::decay_t const& asset2, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_DELETE, account, sequence, fee) + { + setAsset(asset); + setAsset2(asset2); + } + + /** + * @brief Construct a AMMDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_DELETE) + { + throw std::runtime_error("Invalid transaction type for AMMDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMDeleteBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMDeleteBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Build and return the AMMDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AMMDeposit.h b/include/xrpl/protocol_autogen/transactions/AMMDeposit.h new file mode 100644 index 0000000000..8e86339b0a --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMDeposit.h @@ -0,0 +1,338 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMDepositBuilder; + +/** + * @brief Transaction: AMMDeposit + * + * Type: ttAMM_DEPOSIT (36) + * Delegable: Delegation::delegable + * Amendment: featureAMM + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMDepositBuilder to construct new transactions. + */ +class AMMDeposit : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_DEPOSIT; + + /** + * @brief Construct a AMMDeposit transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMDeposit(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMDeposit"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->tx_->at(sfAsset2); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } + + /** + * @brief Get sfAmount2 (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount2() const + { + if (hasAmount2()) + { + return this->tx_->at(sfAmount2); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount2 is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount2() const + { + return this->tx_->isFieldPresent(sfAmount2); + } + + /** + * @brief Get sfEPrice (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getEPrice() const + { + if (hasEPrice()) + { + return this->tx_->at(sfEPrice); + } + return std::nullopt; + } + + /** + * @brief Check if sfEPrice is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasEPrice() const + { + return this->tx_->isFieldPresent(sfEPrice); + } + + /** + * @brief Get sfLPTokenOut (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLPTokenOut() const + { + if (hasLPTokenOut()) + { + return this->tx_->at(sfLPTokenOut); + } + return std::nullopt; + } + + /** + * @brief Check if sfLPTokenOut is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLPTokenOut() const + { + return this->tx_->isFieldPresent(sfLPTokenOut); + } + + /** + * @brief Get sfTradingFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTradingFee() const + { + if (hasTradingFee()) + { + return this->tx_->at(sfTradingFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfTradingFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTradingFee() const + { + return this->tx_->isFieldPresent(sfTradingFee); + } +}; + +/** + * @brief Builder for AMMDeposit transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMDepositBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMDepositBuilder with required fields. + * @param account The account initiating the transaction. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMDepositBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& asset, std::decay_t const& asset2, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_DEPOSIT, account, sequence, fee) + { + setAsset(asset); + setAsset2(asset2); + } + + /** + * @brief Construct a AMMDepositBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMDepositBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_DEPOSIT) + { + throw std::runtime_error("Invalid transaction type for AMMDepositBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfAmount2 (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setAmount2(std::decay_t const& value) + { + object_[sfAmount2] = value; + return *this; + } + + /** + * @brief Set sfEPrice (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setEPrice(std::decay_t const& value) + { + object_[sfEPrice] = value; + return *this; + } + + /** + * @brief Set sfLPTokenOut (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setLPTokenOut(std::decay_t const& value) + { + object_[sfLPTokenOut] = value; + return *this; + } + + /** + * @brief Set sfTradingFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMDepositBuilder& + setTradingFee(std::decay_t const& value) + { + object_[sfTradingFee] = value; + return *this; + } + + /** + * @brief Build and return the AMMDeposit wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMDeposit + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMDeposit{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AMMVote.h b/include/xrpl/protocol_autogen/transactions/AMMVote.h new file mode 100644 index 0000000000..a4e58c9aa4 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMVote.h @@ -0,0 +1,177 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMVoteBuilder; + +/** + * @brief Transaction: AMMVote + * + * Type: ttAMM_VOTE (38) + * Delegable: Delegation::delegable + * Amendment: featureAMM + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMVoteBuilder to construct new transactions. + */ +class AMMVote : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_VOTE; + + /** + * @brief Construct a AMMVote transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMVote(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMVote"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->tx_->at(sfAsset2); + } + + /** + * @brief Get sfTradingFee (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT16::type::value_type + getTradingFee() const + { + return this->tx_->at(sfTradingFee); + } +}; + +/** + * @brief Builder for AMMVote transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMVoteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMVoteBuilder with required fields. + * @param account The account initiating the transaction. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param tradingFee The sfTradingFee field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMVoteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& asset, std::decay_t const& asset2, std::decay_t const& tradingFee, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_VOTE, account, sequence, fee) + { + setAsset(asset); + setAsset2(asset2); + setTradingFee(tradingFee); + } + + /** + * @brief Construct a AMMVoteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMVoteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_VOTE) + { + throw std::runtime_error("Invalid transaction type for AMMVoteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMVoteBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMVoteBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Set sfTradingFee (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMVoteBuilder& + setTradingFee(std::decay_t const& value) + { + object_[sfTradingFee] = value; + return *this; + } + + /** + * @brief Build and return the AMMVote wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMVote + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMVote{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AMMWithdraw.h b/include/xrpl/protocol_autogen/transactions/AMMWithdraw.h new file mode 100644 index 0000000000..da19c546ee --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AMMWithdraw.h @@ -0,0 +1,301 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AMMWithdrawBuilder; + +/** + * @brief Transaction: AMMWithdraw + * + * Type: ttAMM_WITHDRAW (37) + * Delegable: Delegation::delegable + * Amendment: featureAMM + * Privileges: mayDeleteAcct + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AMMWithdrawBuilder to construct new transactions. + */ +class AMMWithdraw : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMM_WITHDRAW; + + /** + * @brief Construct a AMMWithdraw transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AMMWithdraw(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AMMWithdraw"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAsset (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAsset2 (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset2() const + { + return this->tx_->at(sfAsset2); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } + + /** + * @brief Get sfAmount2 (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount2() const + { + if (hasAmount2()) + { + return this->tx_->at(sfAmount2); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount2 is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount2() const + { + return this->tx_->isFieldPresent(sfAmount2); + } + + /** + * @brief Get sfEPrice (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getEPrice() const + { + if (hasEPrice()) + { + return this->tx_->at(sfEPrice); + } + return std::nullopt; + } + + /** + * @brief Check if sfEPrice is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasEPrice() const + { + return this->tx_->isFieldPresent(sfEPrice); + } + + /** + * @brief Get sfLPTokenIn (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLPTokenIn() const + { + if (hasLPTokenIn()) + { + return this->tx_->at(sfLPTokenIn); + } + return std::nullopt; + } + + /** + * @brief Check if sfLPTokenIn is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLPTokenIn() const + { + return this->tx_->isFieldPresent(sfLPTokenIn); + } +}; + +/** + * @brief Builder for AMMWithdraw transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AMMWithdrawBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AMMWithdrawBuilder with required fields. + * @param account The account initiating the transaction. + * @param asset The sfAsset field value. + * @param asset2 The sfAsset2 field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AMMWithdrawBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& asset, std::decay_t const& asset2, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMM_WITHDRAW, account, sequence, fee) + { + setAsset(asset); + setAsset2(asset2); + } + + /** + * @brief Construct a AMMWithdrawBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AMMWithdrawBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMM_WITHDRAW) + { + throw std::runtime_error("Invalid transaction type for AMMWithdrawBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAsset (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMWithdrawBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAsset2 (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AMMWithdrawBuilder& + setAsset2(std::decay_t const& value) + { + object_[sfAsset2] = STIssue(sfAsset2, value); + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMWithdrawBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfAmount2 (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMWithdrawBuilder& + setAmount2(std::decay_t const& value) + { + object_[sfAmount2] = value; + return *this; + } + + /** + * @brief Set sfEPrice (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMWithdrawBuilder& + setEPrice(std::decay_t const& value) + { + object_[sfEPrice] = value; + return *this; + } + + /** + * @brief Set sfLPTokenIn (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AMMWithdrawBuilder& + setLPTokenIn(std::decay_t const& value) + { + object_[sfLPTokenIn] = value; + return *this; + } + + /** + * @brief Build and return the AMMWithdraw wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AMMWithdraw + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AMMWithdraw{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AccountDelete.h b/include/xrpl/protocol_autogen/transactions/AccountDelete.h new file mode 100644 index 0000000000..86ae9af546 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AccountDelete.h @@ -0,0 +1,203 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AccountDeleteBuilder; + +/** + * @brief Transaction: AccountDelete + * + * Type: ttACCOUNT_DELETE (21) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: mustDeleteAcct + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AccountDeleteBuilder to construct new transactions. + */ +class AccountDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttACCOUNT_DELETE; + + /** + * @brief Construct a AccountDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AccountDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AccountDelete"); + } + } + + // Transaction-specific field getters + + /** + * @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 + 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 sfCredentialIDs (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCredentialIDs() const + { + if (hasCredentialIDs()) + { + return this->tx_->at(sfCredentialIDs); + } + return std::nullopt; + } + + /** + * @brief Check if sfCredentialIDs is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCredentialIDs() const + { + return this->tx_->isFieldPresent(sfCredentialIDs); + } +}; + +/** + * @brief Builder for AccountDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AccountDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AccountDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param destination The sfDestination field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + AccountDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& destination, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttACCOUNT_DELETE, account, sequence, fee) + { + setDestination(destination); + } + + /** + * @brief Construct a AccountDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AccountDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttACCOUNT_DELETE) + { + throw std::runtime_error("Invalid transaction type for AccountDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + AccountDeleteBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountDeleteBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfCredentialIDs (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountDeleteBuilder& + setCredentialIDs(std::decay_t const& value) + { + object_[sfCredentialIDs] = value; + return *this; + } + + /** + * @brief Build and return the AccountDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AccountDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AccountDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/AccountSet.h b/include/xrpl/protocol_autogen/transactions/AccountSet.h new file mode 100644 index 0000000000..c00142bd1e --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/AccountSet.h @@ -0,0 +1,475 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class AccountSetBuilder; + +/** + * @brief Transaction: AccountSet + * + * Type: ttACCOUNT_SET (3) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use AccountSetBuilder to construct new transactions. + */ +class AccountSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttACCOUNT_SET; + + /** + * @brief Construct a AccountSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit AccountSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for AccountSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfEmailHash (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getEmailHash() const + { + if (hasEmailHash()) + { + return this->tx_->at(sfEmailHash); + } + return std::nullopt; + } + + /** + * @brief Check if sfEmailHash is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasEmailHash() const + { + return this->tx_->isFieldPresent(sfEmailHash); + } + + /** + * @brief Get sfWalletLocator (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getWalletLocator() const + { + if (hasWalletLocator()) + { + return this->tx_->at(sfWalletLocator); + } + return std::nullopt; + } + + /** + * @brief Check if sfWalletLocator is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasWalletLocator() const + { + return this->tx_->isFieldPresent(sfWalletLocator); + } + + /** + * @brief Get sfWalletSize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getWalletSize() const + { + if (hasWalletSize()) + { + return this->tx_->at(sfWalletSize); + } + return std::nullopt; + } + + /** + * @brief Check if sfWalletSize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasWalletSize() const + { + return this->tx_->isFieldPresent(sfWalletSize); + } + + /** + * @brief Get sfMessageKey (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMessageKey() const + { + if (hasMessageKey()) + { + return this->tx_->at(sfMessageKey); + } + return std::nullopt; + } + + /** + * @brief Check if sfMessageKey is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMessageKey() const + { + return this->tx_->isFieldPresent(sfMessageKey); + } + + /** + * @brief Get sfDomain (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomain() const + { + if (hasDomain()) + { + return this->tx_->at(sfDomain); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomain is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomain() const + { + return this->tx_->isFieldPresent(sfDomain); + } + + /** + * @brief Get sfTransferRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferRate() const + { + if (hasTransferRate()) + { + return this->tx_->at(sfTransferRate); + } + return std::nullopt; + } + + /** + * @brief Check if sfTransferRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferRate() const + { + return this->tx_->isFieldPresent(sfTransferRate); + } + + /** + * @brief Get sfSetFlag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSetFlag() const + { + if (hasSetFlag()) + { + return this->tx_->at(sfSetFlag); + } + return std::nullopt; + } + + /** + * @brief Check if sfSetFlag is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSetFlag() const + { + return this->tx_->isFieldPresent(sfSetFlag); + } + + /** + * @brief Get sfClearFlag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getClearFlag() const + { + if (hasClearFlag()) + { + return this->tx_->at(sfClearFlag); + } + return std::nullopt; + } + + /** + * @brief Check if sfClearFlag is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasClearFlag() const + { + return this->tx_->isFieldPresent(sfClearFlag); + } + + /** + * @brief Get sfTickSize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTickSize() const + { + if (hasTickSize()) + { + return this->tx_->at(sfTickSize); + } + return std::nullopt; + } + + /** + * @brief Check if sfTickSize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTickSize() const + { + return this->tx_->isFieldPresent(sfTickSize); + } + + /** + * @brief Get sfNFTokenMinter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNFTokenMinter() const + { + if (hasNFTokenMinter()) + { + return this->tx_->at(sfNFTokenMinter); + } + return std::nullopt; + } + + /** + * @brief Check if sfNFTokenMinter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNFTokenMinter() const + { + return this->tx_->isFieldPresent(sfNFTokenMinter); + } +}; + +/** + * @brief Builder for AccountSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class AccountSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new AccountSetBuilder 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. + */ + AccountSetBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttACCOUNT_SET, account, sequence, fee) + { + } + + /** + * @brief Construct a AccountSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + AccountSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttACCOUNT_SET) + { + throw std::runtime_error("Invalid transaction type for AccountSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfEmailHash (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setEmailHash(std::decay_t const& value) + { + object_[sfEmailHash] = value; + return *this; + } + + /** + * @brief Set sfWalletLocator (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setWalletLocator(std::decay_t const& value) + { + object_[sfWalletLocator] = value; + return *this; + } + + /** + * @brief Set sfWalletSize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setWalletSize(std::decay_t const& value) + { + object_[sfWalletSize] = value; + return *this; + } + + /** + * @brief Set sfMessageKey (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setMessageKey(std::decay_t const& value) + { + object_[sfMessageKey] = value; + return *this; + } + + /** + * @brief Set sfDomain (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setDomain(std::decay_t const& value) + { + object_[sfDomain] = value; + return *this; + } + + /** + * @brief Set sfTransferRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setTransferRate(std::decay_t const& value) + { + object_[sfTransferRate] = value; + return *this; + } + + /** + * @brief Set sfSetFlag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setSetFlag(std::decay_t const& value) + { + object_[sfSetFlag] = value; + return *this; + } + + /** + * @brief Set sfClearFlag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setClearFlag(std::decay_t const& value) + { + object_[sfClearFlag] = value; + return *this; + } + + /** + * @brief Set sfTickSize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setTickSize(std::decay_t const& value) + { + object_[sfTickSize] = value; + return *this; + } + + /** + * @brief Set sfNFTokenMinter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + AccountSetBuilder& + setNFTokenMinter(std::decay_t const& value) + { + object_[sfNFTokenMinter] = value; + return *this; + } + + /** + * @brief Build and return the AccountSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + AccountSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return AccountSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/Batch.h b/include/xrpl/protocol_autogen/transactions/Batch.h new file mode 100644 index 0000000000..0bb638435c --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/Batch.h @@ -0,0 +1,164 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class BatchBuilder; + +/** + * @brief Transaction: Batch + * + * Type: ttBATCH (71) + * Delegable: Delegation::notDelegable + * Amendment: featureBatch + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use BatchBuilder to construct new transactions. + */ +class Batch : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttBATCH; + + /** + * @brief Construct a Batch transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit Batch(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for Batch"); + } + } + + // Transaction-specific field getters + /** + * @brief Get sfRawTransactions (soeREQUIRED) + * @note This is an untyped field. + * @return The field value. + */ + [[nodiscard]] + STArray const& + getRawTransactions() const + { + return this->tx_->getFieldArray(sfRawTransactions); + } + /** + * @brief Get sfBatchSigners (soeOPTIONAL) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getBatchSigners() const + { + if (this->tx_->isFieldPresent(sfBatchSigners)) + return this->tx_->getFieldArray(sfBatchSigners); + return std::nullopt; + } + + /** + * @brief Check if sfBatchSigners is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBatchSigners() const + { + return this->tx_->isFieldPresent(sfBatchSigners); + } +}; + +/** + * @brief Builder for Batch transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class BatchBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new BatchBuilder with required fields. + * @param account The account initiating the transaction. + * @param rawTransactions The sfRawTransactions field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + BatchBuilder(SF_ACCOUNT::type::value_type account, + STArray const& rawTransactions, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttBATCH, account, sequence, fee) + { + setRawTransactions(rawTransactions); + } + + /** + * @brief Construct a BatchBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + BatchBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttBATCH) + { + throw std::runtime_error("Invalid transaction type for BatchBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfRawTransactions (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + BatchBuilder& + setRawTransactions(STArray const& value) + { + object_.setFieldArray(sfRawTransactions, value); + return *this; + } + + /** + * @brief Set sfBatchSigners (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + BatchBuilder& + setBatchSigners(STArray const& value) + { + object_.setFieldArray(sfBatchSigners, value); + return *this; + } + + /** + * @brief Build and return the Batch wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + Batch + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return Batch{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/CheckCancel.h b/include/xrpl/protocol_autogen/transactions/CheckCancel.h new file mode 100644 index 0000000000..2409e7064c --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/CheckCancel.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class CheckCancelBuilder; + +/** + * @brief Transaction: CheckCancel + * + * Type: ttCHECK_CANCEL (18) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use CheckCancelBuilder to construct new transactions. + */ +class CheckCancel : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCHECK_CANCEL; + + /** + * @brief Construct a CheckCancel transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit CheckCancel(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for CheckCancel"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfCheckID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getCheckID() const + { + return this->tx_->at(sfCheckID); + } +}; + +/** + * @brief Builder for CheckCancel transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class CheckCancelBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new CheckCancelBuilder with required fields. + * @param account The account initiating the transaction. + * @param checkID The sfCheckID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + CheckCancelBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& checkID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCHECK_CANCEL, account, sequence, fee) + { + setCheckID(checkID); + } + + /** + * @brief Construct a CheckCancelBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + CheckCancelBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCHECK_CANCEL) + { + throw std::runtime_error("Invalid transaction type for CheckCancelBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfCheckID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckCancelBuilder& + setCheckID(std::decay_t const& value) + { + object_[sfCheckID] = value; + return *this; + } + + /** + * @brief Build and return the CheckCancel wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + CheckCancel + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return CheckCancel{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/CheckCash.h b/include/xrpl/protocol_autogen/transactions/CheckCash.h new file mode 100644 index 0000000000..2a2bc9c7af --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/CheckCash.h @@ -0,0 +1,203 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class CheckCashBuilder; + +/** + * @brief Transaction: CheckCash + * + * Type: ttCHECK_CASH (17) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use CheckCashBuilder to construct new transactions. + */ +class CheckCash : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCHECK_CASH; + + /** + * @brief Construct a CheckCash transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit CheckCash(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for CheckCash"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfCheckID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getCheckID() const + { + return this->tx_->at(sfCheckID); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } + + /** + * @brief Get sfDeliverMin (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDeliverMin() const + { + if (hasDeliverMin()) + { + return this->tx_->at(sfDeliverMin); + } + return std::nullopt; + } + + /** + * @brief Check if sfDeliverMin is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDeliverMin() const + { + return this->tx_->isFieldPresent(sfDeliverMin); + } +}; + +/** + * @brief Builder for CheckCash transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class CheckCashBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new CheckCashBuilder with required fields. + * @param account The account initiating the transaction. + * @param checkID The sfCheckID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + CheckCashBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& checkID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCHECK_CASH, account, sequence, fee) + { + setCheckID(checkID); + } + + /** + * @brief Construct a CheckCashBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + CheckCashBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCHECK_CASH) + { + throw std::runtime_error("Invalid transaction type for CheckCashBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfCheckID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckCashBuilder& + setCheckID(std::decay_t const& value) + { + object_[sfCheckID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckCashBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfDeliverMin (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckCashBuilder& + setDeliverMin(std::decay_t const& value) + { + object_[sfDeliverMin] = value; + return *this; + } + + /** + * @brief Build and return the CheckCash wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + CheckCash + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return CheckCash{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/CheckCreate.h b/include/xrpl/protocol_autogen/transactions/CheckCreate.h new file mode 100644 index 0000000000..ba209a7fc4 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/CheckCreate.h @@ -0,0 +1,264 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class CheckCreateBuilder; + +/** + * @brief Transaction: CheckCreate + * + * Type: ttCHECK_CREATE (16) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use CheckCreateBuilder to construct new transactions. + */ +class CheckCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCHECK_CREATE; + + /** + * @brief Construct a CheckCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit CheckCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for CheckCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfDestination (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getDestination() const + { + return this->tx_->at(sfDestination); + } + + /** + * @brief Get sfSendMax (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getSendMax() const + { + return this->tx_->at(sfSendMax); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + { + return this->tx_->at(sfExpiration); + } + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->tx_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 sfInvoiceID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getInvoiceID() const + { + if (hasInvoiceID()) + { + return this->tx_->at(sfInvoiceID); + } + return std::nullopt; + } + + /** + * @brief Check if sfInvoiceID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasInvoiceID() const + { + return this->tx_->isFieldPresent(sfInvoiceID); + } +}; + +/** + * @brief Builder for CheckCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class CheckCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new CheckCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param destination The sfDestination field value. + * @param sendMax The sfSendMax field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + CheckCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& destination, std::decay_t const& sendMax, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCHECK_CREATE, account, sequence, fee) + { + setDestination(destination); + setSendMax(sendMax); + } + + /** + * @brief Construct a CheckCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + CheckCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCHECK_CREATE) + { + throw std::runtime_error("Invalid transaction type for CheckCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckCreateBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfSendMax (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CheckCreateBuilder& + setSendMax(std::decay_t const& value) + { + object_[sfSendMax] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckCreateBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckCreateBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfInvoiceID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CheckCreateBuilder& + setInvoiceID(std::decay_t const& value) + { + object_[sfInvoiceID] = value; + return *this; + } + + /** + * @brief Build and return the CheckCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + CheckCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return CheckCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/Clawback.h b/include/xrpl/protocol_autogen/transactions/Clawback.h new file mode 100644 index 0000000000..6c34ceff11 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/Clawback.h @@ -0,0 +1,168 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class ClawbackBuilder; + +/** + * @brief Transaction: Clawback + * + * Type: ttCLAWBACK (30) + * Delegable: Delegation::delegable + * Amendment: featureClawback + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use ClawbackBuilder to construct new transactions. + */ +class Clawback : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCLAWBACK; + + /** + * @brief Construct a Clawback transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit Clawback(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for Clawback"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfHolder (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getHolder() const + { + if (hasHolder()) + { + return this->tx_->at(sfHolder); + } + return std::nullopt; + } + + /** + * @brief Check if sfHolder is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasHolder() const + { + return this->tx_->isFieldPresent(sfHolder); + } +}; + +/** + * @brief Builder for Clawback transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class ClawbackBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new ClawbackBuilder with required fields. + * @param account The account initiating the transaction. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + ClawbackBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCLAWBACK, account, sequence, fee) + { + setAmount(amount); + } + + /** + * @brief Construct a ClawbackBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + ClawbackBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCLAWBACK) + { + throw std::runtime_error("Invalid transaction type for ClawbackBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + ClawbackBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfHolder (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + ClawbackBuilder& + setHolder(std::decay_t const& value) + { + object_[sfHolder] = value; + return *this; + } + + /** + * @brief Build and return the Clawback wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + Clawback + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return Clawback{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/CredentialAccept.h b/include/xrpl/protocol_autogen/transactions/CredentialAccept.h new file mode 100644 index 0000000000..c739e4abcb --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/CredentialAccept.h @@ -0,0 +1,153 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class CredentialAcceptBuilder; + +/** + * @brief Transaction: CredentialAccept + * + * Type: ttCREDENTIAL_ACCEPT (59) + * Delegable: Delegation::delegable + * Amendment: featureCredentials + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use CredentialAcceptBuilder to construct new transactions. + */ +class CredentialAccept : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCREDENTIAL_ACCEPT; + + /** + * @brief Construct a CredentialAccept transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit CredentialAccept(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for CredentialAccept"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfIssuer (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getIssuer() const + { + return this->tx_->at(sfIssuer); + } + + /** + * @brief Get sfCredentialType (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getCredentialType() const + { + return this->tx_->at(sfCredentialType); + } +}; + +/** + * @brief Builder for CredentialAccept transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class CredentialAcceptBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new CredentialAcceptBuilder with required fields. + * @param account The account initiating the transaction. + * @param issuer The sfIssuer field value. + * @param credentialType The sfCredentialType field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + CredentialAcceptBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& issuer, std::decay_t const& credentialType, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCREDENTIAL_ACCEPT, account, sequence, fee) + { + setIssuer(issuer); + setCredentialType(credentialType); + } + + /** + * @brief Construct a CredentialAcceptBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + CredentialAcceptBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCREDENTIAL_ACCEPT) + { + throw std::runtime_error("Invalid transaction type for CredentialAcceptBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfIssuer (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialAcceptBuilder& + setIssuer(std::decay_t const& value) + { + object_[sfIssuer] = value; + return *this; + } + + /** + * @brief Set sfCredentialType (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialAcceptBuilder& + setCredentialType(std::decay_t const& value) + { + object_[sfCredentialType] = value; + return *this; + } + + /** + * @brief Build and return the CredentialAccept wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + CredentialAccept + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return CredentialAccept{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/CredentialCreate.h b/include/xrpl/protocol_autogen/transactions/CredentialCreate.h new file mode 100644 index 0000000000..4da5b3ff47 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/CredentialCreate.h @@ -0,0 +1,227 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class CredentialCreateBuilder; + +/** + * @brief Transaction: CredentialCreate + * + * Type: ttCREDENTIAL_CREATE (58) + * Delegable: Delegation::delegable + * Amendment: featureCredentials + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use CredentialCreateBuilder to construct new transactions. + */ +class CredentialCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCREDENTIAL_CREATE; + + /** + * @brief Construct a CredentialCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit CredentialCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for CredentialCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfSubject (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getSubject() const + { + return this->tx_->at(sfSubject); + } + + /** + * @brief Get sfCredentialType (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getCredentialType() const + { + return this->tx_->at(sfCredentialType); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + { + return this->tx_->at(sfExpiration); + } + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->tx_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + { + return this->tx_->at(sfURI); + } + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->tx_->isFieldPresent(sfURI); + } +}; + +/** + * @brief Builder for CredentialCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class CredentialCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new CredentialCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param subject The sfSubject field value. + * @param credentialType The sfCredentialType field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + CredentialCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& subject, std::decay_t const& credentialType, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCREDENTIAL_CREATE, account, sequence, fee) + { + setSubject(subject); + setCredentialType(credentialType); + } + + /** + * @brief Construct a CredentialCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + CredentialCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCREDENTIAL_CREATE) + { + throw std::runtime_error("Invalid transaction type for CredentialCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfSubject (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialCreateBuilder& + setSubject(std::decay_t const& value) + { + object_[sfSubject] = value; + return *this; + } + + /** + * @brief Set sfCredentialType (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialCreateBuilder& + setCredentialType(std::decay_t const& value) + { + object_[sfCredentialType] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialCreateBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialCreateBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Build and return the CredentialCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + CredentialCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return CredentialCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/CredentialDelete.h b/include/xrpl/protocol_autogen/transactions/CredentialDelete.h new file mode 100644 index 0000000000..bd840ed104 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/CredentialDelete.h @@ -0,0 +1,203 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class CredentialDeleteBuilder; + +/** + * @brief Transaction: CredentialDelete + * + * Type: ttCREDENTIAL_DELETE (60) + * Delegable: Delegation::delegable + * Amendment: featureCredentials + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use CredentialDeleteBuilder to construct new transactions. + */ +class CredentialDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttCREDENTIAL_DELETE; + + /** + * @brief Construct a CredentialDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit CredentialDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for CredentialDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfSubject (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSubject() const + { + if (hasSubject()) + { + return this->tx_->at(sfSubject); + } + return std::nullopt; + } + + /** + * @brief Check if sfSubject is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSubject() const + { + return this->tx_->isFieldPresent(sfSubject); + } + + /** + * @brief Get sfIssuer (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getIssuer() const + { + if (hasIssuer()) + { + return this->tx_->at(sfIssuer); + } + return std::nullopt; + } + + /** + * @brief Check if sfIssuer is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasIssuer() const + { + return this->tx_->isFieldPresent(sfIssuer); + } + + /** + * @brief Get sfCredentialType (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getCredentialType() const + { + return this->tx_->at(sfCredentialType); + } +}; + +/** + * @brief Builder for CredentialDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class CredentialDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new CredentialDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param credentialType The sfCredentialType field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + CredentialDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& credentialType, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttCREDENTIAL_DELETE, account, sequence, fee) + { + setCredentialType(credentialType); + } + + /** + * @brief Construct a CredentialDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + CredentialDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttCREDENTIAL_DELETE) + { + throw std::runtime_error("Invalid transaction type for CredentialDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfSubject (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialDeleteBuilder& + setSubject(std::decay_t const& value) + { + object_[sfSubject] = value; + return *this; + } + + /** + * @brief Set sfIssuer (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + CredentialDeleteBuilder& + setIssuer(std::decay_t const& value) + { + object_[sfIssuer] = value; + return *this; + } + + /** + * @brief Set sfCredentialType (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + CredentialDeleteBuilder& + setCredentialType(std::decay_t const& value) + { + object_[sfCredentialType] = value; + return *this; + } + + /** + * @brief Build and return the CredentialDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + CredentialDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return CredentialDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/DIDDelete.h b/include/xrpl/protocol_autogen/transactions/DIDDelete.h new file mode 100644 index 0000000000..c4e61eb19e --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/DIDDelete.h @@ -0,0 +1,105 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class DIDDeleteBuilder; + +/** + * @brief Transaction: DIDDelete + * + * Type: ttDID_DELETE (50) + * Delegable: Delegation::delegable + * Amendment: featureDID + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use DIDDeleteBuilder to construct new transactions. + */ +class DIDDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttDID_DELETE; + + /** + * @brief Construct a DIDDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit DIDDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for DIDDelete"); + } + } + + // Transaction-specific field getters +}; + +/** + * @brief Builder for DIDDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class DIDDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new DIDDeleteBuilder 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. + */ + DIDDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttDID_DELETE, account, sequence, fee) + { + } + + /** + * @brief Construct a DIDDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + DIDDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttDID_DELETE) + { + throw std::runtime_error("Invalid transaction type for DIDDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Build and return the DIDDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + DIDDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return DIDDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/DIDSet.h b/include/xrpl/protocol_autogen/transactions/DIDSet.h new file mode 100644 index 0000000000..33313d384c --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/DIDSet.h @@ -0,0 +1,216 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class DIDSetBuilder; + +/** + * @brief Transaction: DIDSet + * + * Type: ttDID_SET (49) + * Delegable: Delegation::delegable + * Amendment: featureDID + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use DIDSetBuilder to construct new transactions. + */ +class DIDSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttDID_SET; + + /** + * @brief Construct a DIDSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit DIDSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for DIDSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfDIDDocument (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDIDDocument() const + { + if (hasDIDDocument()) + { + return this->tx_->at(sfDIDDocument); + } + return std::nullopt; + } + + /** + * @brief Check if sfDIDDocument is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDIDDocument() const + { + return this->tx_->isFieldPresent(sfDIDDocument); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + { + return this->tx_->at(sfURI); + } + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->tx_->isFieldPresent(sfURI); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + { + return this->tx_->at(sfData); + } + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->tx_->isFieldPresent(sfData); + } +}; + +/** + * @brief Builder for DIDSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class DIDSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new DIDSetBuilder 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. + */ + DIDSetBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttDID_SET, account, sequence, fee) + { + } + + /** + * @brief Construct a DIDSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + DIDSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttDID_SET) + { + throw std::runtime_error("Invalid transaction type for DIDSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDIDDocument (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DIDSetBuilder& + setDIDDocument(std::decay_t const& value) + { + object_[sfDIDDocument] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DIDSetBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DIDSetBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Build and return the DIDSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + DIDSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return DIDSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/DelegateSet.h b/include/xrpl/protocol_autogen/transactions/DelegateSet.h new file mode 100644 index 0000000000..cac4b3abef --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/DelegateSet.h @@ -0,0 +1,153 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class DelegateSetBuilder; + +/** + * @brief Transaction: DelegateSet + * + * Type: ttDELEGATE_SET (64) + * Delegable: Delegation::notDelegable + * Amendment: featurePermissionDelegationV1_1 + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use DelegateSetBuilder to construct new transactions. + */ +class DelegateSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttDELEGATE_SET; + + /** + * @brief Construct a DelegateSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit DelegateSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for DelegateSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAuthorize (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getAuthorize() const + { + return this->tx_->at(sfAuthorize); + } + /** + * @brief Get sfPermissions (soeREQUIRED) + * @note This is an untyped field. + * @return The field value. + */ + [[nodiscard]] + STArray const& + getPermissions() const + { + return this->tx_->getFieldArray(sfPermissions); + } +}; + +/** + * @brief Builder for DelegateSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class DelegateSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new DelegateSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param authorize The sfAuthorize field value. + * @param permissions The sfPermissions field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + DelegateSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& authorize, STArray const& permissions, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttDELEGATE_SET, account, sequence, fee) + { + setAuthorize(authorize); + setPermissions(permissions); + } + + /** + * @brief Construct a DelegateSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + DelegateSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttDELEGATE_SET) + { + throw std::runtime_error("Invalid transaction type for DelegateSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAuthorize (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateSetBuilder& + setAuthorize(std::decay_t const& value) + { + object_[sfAuthorize] = value; + return *this; + } + + /** + * @brief Set sfPermissions (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + DelegateSetBuilder& + setPermissions(STArray const& value) + { + object_.setFieldArray(sfPermissions, value); + return *this; + } + + /** + * @brief Build and return the DelegateSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + DelegateSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return DelegateSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/DepositPreauth.h b/include/xrpl/protocol_autogen/transactions/DepositPreauth.h new file mode 100644 index 0000000000..eae8b113a9 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/DepositPreauth.h @@ -0,0 +1,249 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class DepositPreauthBuilder; + +/** + * @brief Transaction: DepositPreauth + * + * Type: ttDEPOSIT_PREAUTH (19) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use DepositPreauthBuilder to construct new transactions. + */ +class DepositPreauth : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttDEPOSIT_PREAUTH; + + /** + * @brief Construct a DepositPreauth transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit DepositPreauth(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for DepositPreauth"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAuthorize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAuthorize() const + { + if (hasAuthorize()) + { + return this->tx_->at(sfAuthorize); + } + return std::nullopt; + } + + /** + * @brief Check if sfAuthorize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAuthorize() const + { + return this->tx_->isFieldPresent(sfAuthorize); + } + + /** + * @brief Get sfUnauthorize (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getUnauthorize() const + { + if (hasUnauthorize()) + { + return this->tx_->at(sfUnauthorize); + } + return std::nullopt; + } + + /** + * @brief Check if sfUnauthorize is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasUnauthorize() const + { + return this->tx_->isFieldPresent(sfUnauthorize); + } + /** + * @brief Get sfAuthorizeCredentials (soeOPTIONAL) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getAuthorizeCredentials() const + { + if (this->tx_->isFieldPresent(sfAuthorizeCredentials)) + return this->tx_->getFieldArray(sfAuthorizeCredentials); + return std::nullopt; + } + + /** + * @brief Check if sfAuthorizeCredentials is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAuthorizeCredentials() const + { + return this->tx_->isFieldPresent(sfAuthorizeCredentials); + } + /** + * @brief Get sfUnauthorizeCredentials (soeOPTIONAL) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getUnauthorizeCredentials() const + { + if (this->tx_->isFieldPresent(sfUnauthorizeCredentials)) + return this->tx_->getFieldArray(sfUnauthorizeCredentials); + return std::nullopt; + } + + /** + * @brief Check if sfUnauthorizeCredentials is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasUnauthorizeCredentials() const + { + return this->tx_->isFieldPresent(sfUnauthorizeCredentials); + } +}; + +/** + * @brief Builder for DepositPreauth transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class DepositPreauthBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new DepositPreauthBuilder 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. + */ + DepositPreauthBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttDEPOSIT_PREAUTH, account, sequence, fee) + { + } + + /** + * @brief Construct a DepositPreauthBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + DepositPreauthBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttDEPOSIT_PREAUTH) + { + throw std::runtime_error("Invalid transaction type for DepositPreauthBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAuthorize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setAuthorize(std::decay_t const& value) + { + object_[sfAuthorize] = value; + return *this; + } + + /** + * @brief Set sfUnauthorize (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setUnauthorize(std::decay_t const& value) + { + object_[sfUnauthorize] = value; + return *this; + } + + /** + * @brief Set sfAuthorizeCredentials (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setAuthorizeCredentials(STArray const& value) + { + object_.setFieldArray(sfAuthorizeCredentials, value); + return *this; + } + + /** + * @brief Set sfUnauthorizeCredentials (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + DepositPreauthBuilder& + setUnauthorizeCredentials(STArray const& value) + { + object_.setFieldArray(sfUnauthorizeCredentials, value); + return *this; + } + + /** + * @brief Build and return the DepositPreauth wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + DepositPreauth + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return DepositPreauth{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/EnableAmendment.h b/include/xrpl/protocol_autogen/transactions/EnableAmendment.h new file mode 100644 index 0000000000..0bf3dfd575 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/EnableAmendment.h @@ -0,0 +1,153 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class EnableAmendmentBuilder; + +/** + * @brief Transaction: EnableAmendment + * + * Type: ttAMENDMENT (100) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use EnableAmendmentBuilder to construct new transactions. + */ +class EnableAmendment : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttAMENDMENT; + + /** + * @brief Construct a EnableAmendment transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit EnableAmendment(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for EnableAmendment"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLedgerSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getLedgerSequence() const + { + return this->tx_->at(sfLedgerSequence); + } + + /** + * @brief Get sfAmendment (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getAmendment() const + { + return this->tx_->at(sfAmendment); + } +}; + +/** + * @brief Builder for EnableAmendment transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class EnableAmendmentBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new EnableAmendmentBuilder with required fields. + * @param account The account initiating the transaction. + * @param ledgerSequence The sfLedgerSequence field value. + * @param amendment The sfAmendment field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + EnableAmendmentBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& ledgerSequence, std::decay_t const& amendment, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttAMENDMENT, account, sequence, fee) + { + setLedgerSequence(ledgerSequence); + setAmendment(amendment); + } + + /** + * @brief Construct a EnableAmendmentBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + EnableAmendmentBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttAMENDMENT) + { + throw std::runtime_error("Invalid transaction type for EnableAmendmentBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLedgerSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EnableAmendmentBuilder& + setLedgerSequence(std::decay_t const& value) + { + object_[sfLedgerSequence] = value; + return *this; + } + + /** + * @brief Set sfAmendment (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EnableAmendmentBuilder& + setAmendment(std::decay_t const& value) + { + object_[sfAmendment] = value; + return *this; + } + + /** + * @brief Build and return the EnableAmendment wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + EnableAmendment + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return EnableAmendment{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/EscrowCancel.h b/include/xrpl/protocol_autogen/transactions/EscrowCancel.h new file mode 100644 index 0000000000..a92d5b10ae --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/EscrowCancel.h @@ -0,0 +1,153 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class EscrowCancelBuilder; + +/** + * @brief Transaction: EscrowCancel + * + * Type: ttESCROW_CANCEL (4) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use EscrowCancelBuilder to construct new transactions. + */ +class EscrowCancel : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttESCROW_CANCEL; + + /** + * @brief Construct a EscrowCancel transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit EscrowCancel(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for EscrowCancel"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->tx_->at(sfOwner); + } + + /** + * @brief Get sfOfferSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getOfferSequence() const + { + return this->tx_->at(sfOfferSequence); + } +}; + +/** + * @brief Builder for EscrowCancel transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class EscrowCancelBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new EscrowCancelBuilder with required fields. + * @param account The account initiating the transaction. + * @param owner The sfOwner field value. + * @param offerSequence The sfOfferSequence field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + EscrowCancelBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& owner, std::decay_t const& offerSequence, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttESCROW_CANCEL, account, sequence, fee) + { + setOwner(owner); + setOfferSequence(offerSequence); + } + + /** + * @brief Construct a EscrowCancelBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + EscrowCancelBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttESCROW_CANCEL) + { + throw std::runtime_error("Invalid transaction type for EscrowCancelBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowCancelBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfOfferSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowCancelBuilder& + setOfferSequence(std::decay_t const& value) + { + object_[sfOfferSequence] = value; + return *this; + } + + /** + * @brief Build and return the EscrowCancel wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + EscrowCancel + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return EscrowCancel{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/EscrowCreate.h b/include/xrpl/protocol_autogen/transactions/EscrowCreate.h new file mode 100644 index 0000000000..32dae6cc57 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/EscrowCreate.h @@ -0,0 +1,303 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class EscrowCreateBuilder; + +/** + * @brief Transaction: EscrowCreate + * + * Type: ttESCROW_CREATE (1) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use EscrowCreateBuilder to construct new transactions. + */ +class EscrowCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttESCROW_CREATE; + + /** + * @brief Construct a EscrowCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit EscrowCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for EscrowCreate"); + } + } + + // Transaction-specific field getters + + /** + * @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) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfCondition (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCondition() const + { + if (hasCondition()) + { + return this->tx_->at(sfCondition); + } + return std::nullopt; + } + + /** + * @brief Check if sfCondition is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCondition() const + { + return this->tx_->isFieldPresent(sfCondition); + } + + /** + * @brief Get sfCancelAfter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCancelAfter() const + { + if (hasCancelAfter()) + { + return this->tx_->at(sfCancelAfter); + } + return std::nullopt; + } + + /** + * @brief Check if sfCancelAfter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCancelAfter() const + { + return this->tx_->isFieldPresent(sfCancelAfter); + } + + /** + * @brief Get sfFinishAfter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getFinishAfter() const + { + if (hasFinishAfter()) + { + return this->tx_->at(sfFinishAfter); + } + return std::nullopt; + } + + /** + * @brief Check if sfFinishAfter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasFinishAfter() const + { + return this->tx_->isFieldPresent(sfFinishAfter); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Builder for EscrowCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class EscrowCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new EscrowCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @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. + */ + EscrowCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& destination, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttESCROW_CREATE, account, sequence, fee) + { + setDestination(destination); + setAmount(amount); + } + + /** + * @brief Construct a EscrowCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + EscrowCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttESCROW_CREATE) + { + throw std::runtime_error("Invalid transaction type for EscrowCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowCreateBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + EscrowCreateBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfCondition (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowCreateBuilder& + setCondition(std::decay_t const& value) + { + object_[sfCondition] = value; + return *this; + } + + /** + * @brief Set sfCancelAfter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowCreateBuilder& + setCancelAfter(std::decay_t const& value) + { + object_[sfCancelAfter] = value; + return *this; + } + + /** + * @brief Set sfFinishAfter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowCreateBuilder& + setFinishAfter(std::decay_t const& value) + { + object_[sfFinishAfter] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowCreateBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Build and return the EscrowCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + EscrowCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return EscrowCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/EscrowFinish.h b/include/xrpl/protocol_autogen/transactions/EscrowFinish.h new file mode 100644 index 0000000000..20e9a089fb --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/EscrowFinish.h @@ -0,0 +1,264 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class EscrowFinishBuilder; + +/** + * @brief Transaction: EscrowFinish + * + * Type: ttESCROW_FINISH (2) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use EscrowFinishBuilder to construct new transactions. + */ +class EscrowFinish : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttESCROW_FINISH; + + /** + * @brief Construct a EscrowFinish transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit EscrowFinish(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for EscrowFinish"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfOwner (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getOwner() const + { + return this->tx_->at(sfOwner); + } + + /** + * @brief Get sfOfferSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getOfferSequence() const + { + return this->tx_->at(sfOfferSequence); + } + + /** + * @brief Get sfFulfillment (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getFulfillment() const + { + if (hasFulfillment()) + { + return this->tx_->at(sfFulfillment); + } + return std::nullopt; + } + + /** + * @brief Check if sfFulfillment is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasFulfillment() const + { + return this->tx_->isFieldPresent(sfFulfillment); + } + + /** + * @brief Get sfCondition (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCondition() const + { + if (hasCondition()) + { + return this->tx_->at(sfCondition); + } + return std::nullopt; + } + + /** + * @brief Check if sfCondition is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCondition() const + { + return this->tx_->isFieldPresent(sfCondition); + } + + /** + * @brief Get sfCredentialIDs (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCredentialIDs() const + { + if (hasCredentialIDs()) + { + return this->tx_->at(sfCredentialIDs); + } + return std::nullopt; + } + + /** + * @brief Check if sfCredentialIDs is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCredentialIDs() const + { + return this->tx_->isFieldPresent(sfCredentialIDs); + } +}; + +/** + * @brief Builder for EscrowFinish transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class EscrowFinishBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new EscrowFinishBuilder with required fields. + * @param account The account initiating the transaction. + * @param owner The sfOwner field value. + * @param offerSequence The sfOfferSequence field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + EscrowFinishBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& owner, std::decay_t const& offerSequence, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttESCROW_FINISH, account, sequence, fee) + { + setOwner(owner); + setOfferSequence(offerSequence); + } + + /** + * @brief Construct a EscrowFinishBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + EscrowFinishBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttESCROW_FINISH) + { + throw std::runtime_error("Invalid transaction type for EscrowFinishBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfOwner (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowFinishBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfOfferSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + EscrowFinishBuilder& + setOfferSequence(std::decay_t const& value) + { + object_[sfOfferSequence] = value; + return *this; + } + + /** + * @brief Set sfFulfillment (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowFinishBuilder& + setFulfillment(std::decay_t const& value) + { + object_[sfFulfillment] = value; + return *this; + } + + /** + * @brief Set sfCondition (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowFinishBuilder& + setCondition(std::decay_t const& value) + { + object_[sfCondition] = value; + return *this; + } + + /** + * @brief Set sfCredentialIDs (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + EscrowFinishBuilder& + setCredentialIDs(std::decay_t const& value) + { + object_[sfCredentialIDs] = value; + return *this; + } + + /** + * @brief Build and return the EscrowFinish wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + EscrowFinish + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return EscrowFinish{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LedgerStateFix.h b/include/xrpl/protocol_autogen/transactions/LedgerStateFix.h new file mode 100644 index 0000000000..6f60b81a04 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LedgerStateFix.h @@ -0,0 +1,166 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LedgerStateFixBuilder; + +/** + * @brief Transaction: LedgerStateFix + * + * Type: ttLEDGER_STATE_FIX (53) + * Delegable: Delegation::delegable + * Amendment: fixNFTokenPageLinks + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LedgerStateFixBuilder to construct new transactions. + */ +class LedgerStateFix : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLEDGER_STATE_FIX; + + /** + * @brief Construct a LedgerStateFix transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LedgerStateFix(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LedgerStateFix"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLedgerFixType (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT16::type::value_type + getLedgerFixType() const + { + return this->tx_->at(sfLedgerFixType); + } + + /** + * @brief Get sfOwner (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwner() const + { + if (hasOwner()) + { + return this->tx_->at(sfOwner); + } + return std::nullopt; + } + + /** + * @brief Check if sfOwner is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwner() const + { + return this->tx_->isFieldPresent(sfOwner); + } +}; + +/** + * @brief Builder for LedgerStateFix transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LedgerStateFixBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LedgerStateFixBuilder with required fields. + * @param account The account initiating the transaction. + * @param ledgerFixType The sfLedgerFixType field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LedgerStateFixBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& ledgerFixType, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLEDGER_STATE_FIX, account, sequence, fee) + { + setLedgerFixType(ledgerFixType); + } + + /** + * @brief Construct a LedgerStateFixBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LedgerStateFixBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLEDGER_STATE_FIX) + { + throw std::runtime_error("Invalid transaction type for LedgerStateFixBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLedgerFixType (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LedgerStateFixBuilder& + setLedgerFixType(std::decay_t const& value) + { + object_[sfLedgerFixType] = value; + return *this; + } + + /** + * @brief Set sfOwner (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LedgerStateFixBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Build and return the LedgerStateFix wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LedgerStateFix + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LedgerStateFix{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverClawback.h b/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverClawback.h new file mode 100644 index 0000000000..d8a9d9d52a --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverClawback.h @@ -0,0 +1,181 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanBrokerCoverClawbackBuilder; + +/** + * @brief Transaction: LoanBrokerCoverClawback + * + * Type: ttLOAN_BROKER_COVER_CLAWBACK (78) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanBrokerCoverClawbackBuilder to construct new transactions. + */ +class LoanBrokerCoverClawback : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_BROKER_COVER_CLAWBACK; + + /** + * @brief Construct a LoanBrokerCoverClawback transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanBrokerCoverClawback(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerCoverClawback"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanBrokerID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanBrokerID() const + { + if (hasLoanBrokerID()) + { + return this->tx_->at(sfLoanBrokerID); + } + return std::nullopt; + } + + /** + * @brief Check if sfLoanBrokerID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanBrokerID() const + { + return this->tx_->isFieldPresent(sfLoanBrokerID); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } +}; + +/** + * @brief Builder for LoanBrokerCoverClawback transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanBrokerCoverClawbackBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanBrokerCoverClawbackBuilder 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. + */ + LoanBrokerCoverClawbackBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_BROKER_COVER_CLAWBACK, account, sequence, fee) + { + } + + /** + * @brief Construct a LoanBrokerCoverClawbackBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanBrokerCoverClawbackBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_BROKER_COVER_CLAWBACK) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerCoverClawbackBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanBrokerID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverClawbackBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverClawbackBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Build and return the LoanBrokerCoverClawback wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanBrokerCoverClawback + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanBrokerCoverClawback{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverDeposit.h b/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverDeposit.h new file mode 100644 index 0000000000..baa567a7ac --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverDeposit.h @@ -0,0 +1,155 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanBrokerCoverDepositBuilder; + +/** + * @brief Transaction: LoanBrokerCoverDeposit + * + * Type: ttLOAN_BROKER_COVER_DEPOSIT (76) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanBrokerCoverDepositBuilder to construct new transactions. + */ +class LoanBrokerCoverDeposit : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_BROKER_COVER_DEPOSIT; + + /** + * @brief Construct a LoanBrokerCoverDeposit transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanBrokerCoverDeposit(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerCoverDeposit"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanBrokerID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanBrokerID() const + { + return this->tx_->at(sfLoanBrokerID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } +}; + +/** + * @brief Builder for LoanBrokerCoverDeposit transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanBrokerCoverDepositBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanBrokerCoverDepositBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanBrokerID The sfLoanBrokerID field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanBrokerCoverDepositBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanBrokerID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_BROKER_COVER_DEPOSIT, account, sequence, fee) + { + setLoanBrokerID(loanBrokerID); + setAmount(amount); + } + + /** + * @brief Construct a LoanBrokerCoverDepositBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanBrokerCoverDepositBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_BROKER_COVER_DEPOSIT) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerCoverDepositBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanBrokerID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverDepositBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverDepositBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Build and return the LoanBrokerCoverDeposit wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanBrokerCoverDeposit + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanBrokerCoverDeposit{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverWithdraw.h b/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverWithdraw.h new file mode 100644 index 0000000000..3690b6a40a --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanBrokerCoverWithdraw.h @@ -0,0 +1,229 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanBrokerCoverWithdrawBuilder; + +/** + * @brief Transaction: LoanBrokerCoverWithdraw + * + * Type: ttLOAN_BROKER_COVER_WITHDRAW (77) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: mayAuthorizeMPT + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanBrokerCoverWithdrawBuilder to construct new transactions. + */ +class LoanBrokerCoverWithdraw : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_BROKER_COVER_WITHDRAW; + + /** + * @brief Construct a LoanBrokerCoverWithdraw transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanBrokerCoverWithdraw(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerCoverWithdraw"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanBrokerID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanBrokerID() const + { + return this->tx_->at(sfLoanBrokerID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfDestination (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Builder for LoanBrokerCoverWithdraw transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanBrokerCoverWithdrawBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanBrokerCoverWithdrawBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanBrokerID The sfLoanBrokerID field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanBrokerCoverWithdrawBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanBrokerID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_BROKER_COVER_WITHDRAW, account, sequence, fee) + { + setLoanBrokerID(loanBrokerID); + setAmount(amount); + } + + /** + * @brief Construct a LoanBrokerCoverWithdrawBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanBrokerCoverWithdrawBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_BROKER_COVER_WITHDRAW) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerCoverWithdrawBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanBrokerID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverWithdrawBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverWithdrawBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverWithdrawBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerCoverWithdrawBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Build and return the LoanBrokerCoverWithdraw wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanBrokerCoverWithdraw + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanBrokerCoverWithdraw{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanBrokerDelete.h b/include/xrpl/protocol_autogen/transactions/LoanBrokerDelete.h new file mode 100644 index 0000000000..2c174ae500 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanBrokerDelete.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanBrokerDeleteBuilder; + +/** + * @brief Transaction: LoanBrokerDelete + * + * Type: ttLOAN_BROKER_DELETE (75) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: mustDeleteAcct | mayAuthorizeMPT + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanBrokerDeleteBuilder to construct new transactions. + */ +class LoanBrokerDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_BROKER_DELETE; + + /** + * @brief Construct a LoanBrokerDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanBrokerDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanBrokerID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanBrokerID() const + { + return this->tx_->at(sfLoanBrokerID); + } +}; + +/** + * @brief Builder for LoanBrokerDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanBrokerDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanBrokerDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanBrokerID The sfLoanBrokerID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanBrokerDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanBrokerID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_BROKER_DELETE, account, sequence, fee) + { + setLoanBrokerID(loanBrokerID); + } + + /** + * @brief Construct a LoanBrokerDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanBrokerDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_BROKER_DELETE) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanBrokerID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerDeleteBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Build and return the LoanBrokerDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanBrokerDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanBrokerDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanBrokerSet.h b/include/xrpl/protocol_autogen/transactions/LoanBrokerSet.h new file mode 100644 index 0000000000..ba6ca06266 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanBrokerSet.h @@ -0,0 +1,351 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanBrokerSetBuilder; + +/** + * @brief Transaction: LoanBrokerSet + * + * Type: ttLOAN_BROKER_SET (74) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: createPseudoAcct | mayAuthorizeMPT + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanBrokerSetBuilder to construct new transactions. + */ +class LoanBrokerSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_BROKER_SET; + + /** + * @brief Construct a LoanBrokerSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanBrokerSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->tx_->at(sfVaultID); + } + + /** + * @brief Get sfLoanBrokerID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanBrokerID() const + { + if (hasLoanBrokerID()) + { + return this->tx_->at(sfLoanBrokerID); + } + return std::nullopt; + } + + /** + * @brief Check if sfLoanBrokerID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanBrokerID() const + { + return this->tx_->isFieldPresent(sfLoanBrokerID); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + { + return this->tx_->at(sfData); + } + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->tx_->isFieldPresent(sfData); + } + + /** + * @brief Get sfManagementFeeRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getManagementFeeRate() const + { + if (hasManagementFeeRate()) + { + return this->tx_->at(sfManagementFeeRate); + } + return std::nullopt; + } + + /** + * @brief Check if sfManagementFeeRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasManagementFeeRate() const + { + return this->tx_->isFieldPresent(sfManagementFeeRate); + } + + /** + * @brief Get sfDebtMaximum (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDebtMaximum() const + { + if (hasDebtMaximum()) + { + return this->tx_->at(sfDebtMaximum); + } + return std::nullopt; + } + + /** + * @brief Check if sfDebtMaximum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDebtMaximum() const + { + return this->tx_->isFieldPresent(sfDebtMaximum); + } + + /** + * @brief Get sfCoverRateMinimum (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCoverRateMinimum() const + { + if (hasCoverRateMinimum()) + { + return this->tx_->at(sfCoverRateMinimum); + } + return std::nullopt; + } + + /** + * @brief Check if sfCoverRateMinimum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCoverRateMinimum() const + { + return this->tx_->isFieldPresent(sfCoverRateMinimum); + } + + /** + * @brief Get sfCoverRateLiquidation (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCoverRateLiquidation() const + { + if (hasCoverRateLiquidation()) + { + return this->tx_->at(sfCoverRateLiquidation); + } + return std::nullopt; + } + + /** + * @brief Check if sfCoverRateLiquidation is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCoverRateLiquidation() const + { + return this->tx_->isFieldPresent(sfCoverRateLiquidation); + } +}; + +/** + * @brief Builder for LoanBrokerSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanBrokerSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanBrokerSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param vaultID The sfVaultID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanBrokerSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& vaultID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_BROKER_SET, account, sequence, fee) + { + setVaultID(vaultID); + } + + /** + * @brief Construct a LoanBrokerSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanBrokerSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_BROKER_SET) + { + throw std::runtime_error("Invalid transaction type for LoanBrokerSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfLoanBrokerID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Set sfManagementFeeRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setManagementFeeRate(std::decay_t const& value) + { + object_[sfManagementFeeRate] = value; + return *this; + } + + /** + * @brief Set sfDebtMaximum (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setDebtMaximum(std::decay_t const& value) + { + object_[sfDebtMaximum] = value; + return *this; + } + + /** + * @brief Set sfCoverRateMinimum (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setCoverRateMinimum(std::decay_t const& value) + { + object_[sfCoverRateMinimum] = value; + return *this; + } + + /** + * @brief Set sfCoverRateLiquidation (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanBrokerSetBuilder& + setCoverRateLiquidation(std::decay_t const& value) + { + object_[sfCoverRateLiquidation] = value; + return *this; + } + + /** + * @brief Build and return the LoanBrokerSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanBrokerSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanBrokerSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanDelete.h b/include/xrpl/protocol_autogen/transactions/LoanDelete.h new file mode 100644 index 0000000000..df1b49d17e --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanDelete.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanDeleteBuilder; + +/** + * @brief Transaction: LoanDelete + * + * Type: ttLOAN_DELETE (81) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanDeleteBuilder to construct new transactions. + */ +class LoanDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_DELETE; + + /** + * @brief Construct a LoanDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanID() const + { + return this->tx_->at(sfLoanID); + } +}; + +/** + * @brief Builder for LoanDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanID The sfLoanID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_DELETE, account, sequence, fee) + { + setLoanID(loanID); + } + + /** + * @brief Construct a LoanDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_DELETE) + { + throw std::runtime_error("Invalid transaction type for LoanDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanDeleteBuilder& + setLoanID(std::decay_t const& value) + { + object_[sfLoanID] = value; + return *this; + } + + /** + * @brief Build and return the LoanDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanManage.h b/include/xrpl/protocol_autogen/transactions/LoanManage.h new file mode 100644 index 0000000000..3da31e4487 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanManage.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanManageBuilder; + +/** + * @brief Transaction: LoanManage + * + * Type: ttLOAN_MANAGE (82) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: mayModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanManageBuilder to construct new transactions. + */ +class LoanManage : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_MANAGE; + + /** + * @brief Construct a LoanManage transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanManage(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanManage"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanID() const + { + return this->tx_->at(sfLoanID); + } +}; + +/** + * @brief Builder for LoanManage transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanManageBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanManageBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanID The sfLoanID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanManageBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_MANAGE, account, sequence, fee) + { + setLoanID(loanID); + } + + /** + * @brief Construct a LoanManageBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanManageBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_MANAGE) + { + throw std::runtime_error("Invalid transaction type for LoanManageBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanManageBuilder& + setLoanID(std::decay_t const& value) + { + object_[sfLoanID] = value; + return *this; + } + + /** + * @brief Build and return the LoanManage wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanManage + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanManage{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanPay.h b/include/xrpl/protocol_autogen/transactions/LoanPay.h new file mode 100644 index 0000000000..e0b4376e18 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanPay.h @@ -0,0 +1,155 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanPayBuilder; + +/** + * @brief Transaction: LoanPay + * + * Type: ttLOAN_PAY (84) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: mayAuthorizeMPT | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanPayBuilder to construct new transactions. + */ +class LoanPay : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_PAY; + + /** + * @brief Construct a LoanPay transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanPay(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanPay"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanID() const + { + return this->tx_->at(sfLoanID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } +}; + +/** + * @brief Builder for LoanPay transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanPayBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanPayBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanID The sfLoanID field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanPayBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_PAY, account, sequence, fee) + { + setLoanID(loanID); + setAmount(amount); + } + + /** + * @brief Construct a LoanPayBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanPayBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_PAY) + { + throw std::runtime_error("Invalid transaction type for LoanPayBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanPayBuilder& + setLoanID(std::decay_t const& value) + { + object_[sfLoanID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + LoanPayBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Build and return the LoanPay wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanPay + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanPay{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/LoanSet.h b/include/xrpl/protocol_autogen/transactions/LoanSet.h new file mode 100644 index 0000000000..7d6181f517 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanSet.h @@ -0,0 +1,706 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class LoanSetBuilder; + +/** + * @brief Transaction: LoanSet + * + * Type: ttLOAN_SET (80) + * Delegable: Delegation::notDelegable + * Amendment: featureLendingProtocol + * Privileges: mayAuthorizeMPT | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanSetBuilder to construct new transactions. + */ +class LoanSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_SET; + + /** + * @brief Construct a LoanSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLoanBrokerID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getLoanBrokerID() const + { + return this->tx_->at(sfLoanBrokerID); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + { + return this->tx_->at(sfData); + } + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->tx_->isFieldPresent(sfData); + } + + /** + * @brief Get sfCounterparty (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCounterparty() const + { + if (hasCounterparty()) + { + return this->tx_->at(sfCounterparty); + } + return std::nullopt; + } + + /** + * @brief Check if sfCounterparty is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCounterparty() const + { + return this->tx_->isFieldPresent(sfCounterparty); + } + /** + * @brief Get sfCounterpartySignature (soeOPTIONAL) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional + getCounterpartySignature() const + { + if (this->tx_->isFieldPresent(sfCounterpartySignature)) + return this->tx_->getFieldObject(sfCounterpartySignature); + return std::nullopt; + } + + /** + * @brief Check if sfCounterpartySignature is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCounterpartySignature() const + { + return this->tx_->isFieldPresent(sfCounterpartySignature); + } + + /** + * @brief Get sfLoanOriginationFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanOriginationFee() const + { + if (hasLoanOriginationFee()) + { + return this->tx_->at(sfLoanOriginationFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfLoanOriginationFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanOriginationFee() const + { + return this->tx_->isFieldPresent(sfLoanOriginationFee); + } + + /** + * @brief Get sfLoanServiceFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLoanServiceFee() const + { + if (hasLoanServiceFee()) + { + return this->tx_->at(sfLoanServiceFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfLoanServiceFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLoanServiceFee() const + { + return this->tx_->isFieldPresent(sfLoanServiceFee); + } + + /** + * @brief Get sfLatePaymentFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLatePaymentFee() const + { + if (hasLatePaymentFee()) + { + return this->tx_->at(sfLatePaymentFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfLatePaymentFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLatePaymentFee() const + { + return this->tx_->isFieldPresent(sfLatePaymentFee); + } + + /** + * @brief Get sfClosePaymentFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getClosePaymentFee() const + { + if (hasClosePaymentFee()) + { + return this->tx_->at(sfClosePaymentFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfClosePaymentFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasClosePaymentFee() const + { + return this->tx_->isFieldPresent(sfClosePaymentFee); + } + + /** + * @brief Get sfOverpaymentFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOverpaymentFee() const + { + if (hasOverpaymentFee()) + { + return this->tx_->at(sfOverpaymentFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfOverpaymentFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOverpaymentFee() const + { + return this->tx_->isFieldPresent(sfOverpaymentFee); + } + + /** + * @brief Get sfInterestRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getInterestRate() const + { + if (hasInterestRate()) + { + return this->tx_->at(sfInterestRate); + } + return std::nullopt; + } + + /** + * @brief Check if sfInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasInterestRate() const + { + return this->tx_->isFieldPresent(sfInterestRate); + } + + /** + * @brief Get sfLateInterestRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLateInterestRate() const + { + if (hasLateInterestRate()) + { + return this->tx_->at(sfLateInterestRate); + } + return std::nullopt; + } + + /** + * @brief Check if sfLateInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLateInterestRate() const + { + return this->tx_->isFieldPresent(sfLateInterestRate); + } + + /** + * @brief Get sfCloseInterestRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCloseInterestRate() const + { + if (hasCloseInterestRate()) + { + return this->tx_->at(sfCloseInterestRate); + } + return std::nullopt; + } + + /** + * @brief Check if sfCloseInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCloseInterestRate() const + { + return this->tx_->isFieldPresent(sfCloseInterestRate); + } + + /** + * @brief Get sfOverpaymentInterestRate (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOverpaymentInterestRate() const + { + if (hasOverpaymentInterestRate()) + { + return this->tx_->at(sfOverpaymentInterestRate); + } + return std::nullopt; + } + + /** + * @brief Check if sfOverpaymentInterestRate is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOverpaymentInterestRate() const + { + return this->tx_->isFieldPresent(sfOverpaymentInterestRate); + } + + /** + * @brief Get sfPrincipalRequested (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_NUMBER::type::value_type + getPrincipalRequested() const + { + return this->tx_->at(sfPrincipalRequested); + } + + /** + * @brief Get sfPaymentTotal (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPaymentTotal() const + { + if (hasPaymentTotal()) + { + return this->tx_->at(sfPaymentTotal); + } + return std::nullopt; + } + + /** + * @brief Check if sfPaymentTotal is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPaymentTotal() const + { + return this->tx_->isFieldPresent(sfPaymentTotal); + } + + /** + * @brief Get sfPaymentInterval (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPaymentInterval() const + { + if (hasPaymentInterval()) + { + return this->tx_->at(sfPaymentInterval); + } + return std::nullopt; + } + + /** + * @brief Check if sfPaymentInterval is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPaymentInterval() const + { + return this->tx_->isFieldPresent(sfPaymentInterval); + } + + /** + * @brief Get sfGracePeriod (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getGracePeriod() const + { + if (hasGracePeriod()) + { + return this->tx_->at(sfGracePeriod); + } + return std::nullopt; + } + + /** + * @brief Check if sfGracePeriod is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasGracePeriod() const + { + return this->tx_->isFieldPresent(sfGracePeriod); + } +}; + +/** + * @brief Builder for LoanSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param loanBrokerID The sfLoanBrokerID field value. + * @param principalRequested The sfPrincipalRequested field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + LoanSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanBrokerID, std::decay_t const& principalRequested, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_SET, account, sequence, fee) + { + setLoanBrokerID(loanBrokerID); + setPrincipalRequested(principalRequested); + } + + /** + * @brief Construct a LoanSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_SET) + { + throw std::runtime_error("Invalid transaction type for LoanSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanBrokerID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setLoanBrokerID(std::decay_t const& value) + { + object_[sfLoanBrokerID] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Set sfCounterparty (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setCounterparty(std::decay_t const& value) + { + object_[sfCounterparty] = value; + return *this; + } + + /** + * @brief Set sfCounterpartySignature (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setCounterpartySignature(STObject const& value) + { + object_.setFieldObject(sfCounterpartySignature, value); + return *this; + } + + /** + * @brief Set sfLoanOriginationFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setLoanOriginationFee(std::decay_t const& value) + { + object_[sfLoanOriginationFee] = value; + return *this; + } + + /** + * @brief Set sfLoanServiceFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setLoanServiceFee(std::decay_t const& value) + { + object_[sfLoanServiceFee] = value; + return *this; + } + + /** + * @brief Set sfLatePaymentFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setLatePaymentFee(std::decay_t const& value) + { + object_[sfLatePaymentFee] = value; + return *this; + } + + /** + * @brief Set sfClosePaymentFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setClosePaymentFee(std::decay_t const& value) + { + object_[sfClosePaymentFee] = value; + return *this; + } + + /** + * @brief Set sfOverpaymentFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setOverpaymentFee(std::decay_t const& value) + { + object_[sfOverpaymentFee] = value; + return *this; + } + + /** + * @brief Set sfInterestRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setInterestRate(std::decay_t const& value) + { + object_[sfInterestRate] = value; + return *this; + } + + /** + * @brief Set sfLateInterestRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setLateInterestRate(std::decay_t const& value) + { + object_[sfLateInterestRate] = value; + return *this; + } + + /** + * @brief Set sfCloseInterestRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setCloseInterestRate(std::decay_t const& value) + { + object_[sfCloseInterestRate] = value; + return *this; + } + + /** + * @brief Set sfOverpaymentInterestRate (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setOverpaymentInterestRate(std::decay_t const& value) + { + object_[sfOverpaymentInterestRate] = value; + return *this; + } + + /** + * @brief Set sfPrincipalRequested (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setPrincipalRequested(std::decay_t const& value) + { + object_[sfPrincipalRequested] = value; + return *this; + } + + /** + * @brief Set sfPaymentTotal (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setPaymentTotal(std::decay_t const& value) + { + object_[sfPaymentTotal] = value; + return *this; + } + + /** + * @brief Set sfPaymentInterval (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setPaymentInterval(std::decay_t const& value) + { + object_[sfPaymentInterval] = value; + return *this; + } + + /** + * @brief Set sfGracePeriod (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setGracePeriod(std::decay_t const& value) + { + object_[sfGracePeriod] = value; + return *this; + } + + /** + * @brief Build and return the LoanSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/MPTokenAuthorize.h b/include/xrpl/protocol_autogen/transactions/MPTokenAuthorize.h new file mode 100644 index 0000000000..a4641f5dc0 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/MPTokenAuthorize.h @@ -0,0 +1,166 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class MPTokenAuthorizeBuilder; + +/** + * @brief Transaction: MPTokenAuthorize + * + * Type: ttMPTOKEN_AUTHORIZE (57) + * Delegable: Delegation::delegable + * Amendment: featureMPTokensV1 + * Privileges: mustAuthorizeMPT + * + * Immutable wrapper around STTx providing type-safe field access. + * Use MPTokenAuthorizeBuilder to construct new transactions. + */ +class MPTokenAuthorize : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttMPTOKEN_AUTHORIZE; + + /** + * @brief Construct a MPTokenAuthorize transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit MPTokenAuthorize(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for MPTokenAuthorize"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfMPTokenIssuanceID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT192::type::value_type + getMPTokenIssuanceID() const + { + return this->tx_->at(sfMPTokenIssuanceID); + } + + /** + * @brief Get sfHolder (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getHolder() const + { + if (hasHolder()) + { + return this->tx_->at(sfHolder); + } + return std::nullopt; + } + + /** + * @brief Check if sfHolder is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasHolder() const + { + return this->tx_->isFieldPresent(sfHolder); + } +}; + +/** + * @brief Builder for MPTokenAuthorize transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class MPTokenAuthorizeBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new MPTokenAuthorizeBuilder with required fields. + * @param account The account initiating the transaction. + * @param mPTokenIssuanceID The sfMPTokenIssuanceID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + MPTokenAuthorizeBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& mPTokenIssuanceID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttMPTOKEN_AUTHORIZE, account, sequence, fee) + { + setMPTokenIssuanceID(mPTokenIssuanceID); + } + + /** + * @brief Construct a MPTokenAuthorizeBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + MPTokenAuthorizeBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttMPTOKEN_AUTHORIZE) + { + throw std::runtime_error("Invalid transaction type for MPTokenAuthorizeBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfMPTokenIssuanceID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenAuthorizeBuilder& + setMPTokenIssuanceID(std::decay_t const& value) + { + object_[sfMPTokenIssuanceID] = value; + return *this; + } + + /** + * @brief Set sfHolder (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenAuthorizeBuilder& + setHolder(std::decay_t const& value) + { + object_[sfHolder] = value; + return *this; + } + + /** + * @brief Build and return the MPTokenAuthorize wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + MPTokenAuthorize + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return MPTokenAuthorize{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceCreate.h b/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceCreate.h new file mode 100644 index 0000000000..6f5c50fc4a --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceCreate.h @@ -0,0 +1,327 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class MPTokenIssuanceCreateBuilder; + +/** + * @brief Transaction: MPTokenIssuanceCreate + * + * Type: ttMPTOKEN_ISSUANCE_CREATE (54) + * Delegable: Delegation::delegable + * Amendment: featureMPTokensV1 + * Privileges: createMPTIssuance + * + * Immutable wrapper around STTx providing type-safe field access. + * Use MPTokenIssuanceCreateBuilder to construct new transactions. + */ +class MPTokenIssuanceCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttMPTOKEN_ISSUANCE_CREATE; + + /** + * @brief Construct a MPTokenIssuanceCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit MPTokenIssuanceCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for MPTokenIssuanceCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAssetScale (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetScale() const + { + if (hasAssetScale()) + { + return this->tx_->at(sfAssetScale); + } + return std::nullopt; + } + + /** + * @brief Check if sfAssetScale is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetScale() const + { + return this->tx_->isFieldPresent(sfAssetScale); + } + + /** + * @brief Get sfTransferFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferFee() const + { + if (hasTransferFee()) + { + return this->tx_->at(sfTransferFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfTransferFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferFee() const + { + return this->tx_->isFieldPresent(sfTransferFee); + } + + /** + * @brief Get sfMaximumAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMaximumAmount() const + { + if (hasMaximumAmount()) + { + return this->tx_->at(sfMaximumAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfMaximumAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMaximumAmount() const + { + return this->tx_->isFieldPresent(sfMaximumAmount); + } + + /** + * @brief Get sfMPTokenMetadata (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMPTokenMetadata() const + { + if (hasMPTokenMetadata()) + { + return this->tx_->at(sfMPTokenMetadata); + } + return std::nullopt; + } + + /** + * @brief Check if sfMPTokenMetadata is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMPTokenMetadata() const + { + return this->tx_->isFieldPresent(sfMPTokenMetadata); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } + + /** + * @brief Get sfMutableFlags (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMutableFlags() const + { + if (hasMutableFlags()) + { + return this->tx_->at(sfMutableFlags); + } + return std::nullopt; + } + + /** + * @brief Check if sfMutableFlags is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMutableFlags() const + { + return this->tx_->isFieldPresent(sfMutableFlags); + } +}; + +/** + * @brief Builder for MPTokenIssuanceCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class MPTokenIssuanceCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new MPTokenIssuanceCreateBuilder 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. + */ + MPTokenIssuanceCreateBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttMPTOKEN_ISSUANCE_CREATE, account, sequence, fee) + { + } + + /** + * @brief Construct a MPTokenIssuanceCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + MPTokenIssuanceCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttMPTOKEN_ISSUANCE_CREATE) + { + throw std::runtime_error("Invalid transaction type for MPTokenIssuanceCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAssetScale (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceCreateBuilder& + setAssetScale(std::decay_t const& value) + { + object_[sfAssetScale] = value; + return *this; + } + + /** + * @brief Set sfTransferFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceCreateBuilder& + setTransferFee(std::decay_t const& value) + { + object_[sfTransferFee] = value; + return *this; + } + + /** + * @brief Set sfMaximumAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceCreateBuilder& + setMaximumAmount(std::decay_t const& value) + { + object_[sfMaximumAmount] = value; + return *this; + } + + /** + * @brief Set sfMPTokenMetadata (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceCreateBuilder& + setMPTokenMetadata(std::decay_t const& value) + { + object_[sfMPTokenMetadata] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceCreateBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfMutableFlags (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceCreateBuilder& + setMutableFlags(std::decay_t const& value) + { + object_[sfMutableFlags] = value; + return *this; + } + + /** + * @brief Build and return the MPTokenIssuanceCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + MPTokenIssuanceCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return MPTokenIssuanceCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceDestroy.h b/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceDestroy.h new file mode 100644 index 0000000000..28d2e49971 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceDestroy.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class MPTokenIssuanceDestroyBuilder; + +/** + * @brief Transaction: MPTokenIssuanceDestroy + * + * Type: ttMPTOKEN_ISSUANCE_DESTROY (55) + * Delegable: Delegation::delegable + * Amendment: featureMPTokensV1 + * Privileges: destroyMPTIssuance + * + * Immutable wrapper around STTx providing type-safe field access. + * Use MPTokenIssuanceDestroyBuilder to construct new transactions. + */ +class MPTokenIssuanceDestroy : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttMPTOKEN_ISSUANCE_DESTROY; + + /** + * @brief Construct a MPTokenIssuanceDestroy transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit MPTokenIssuanceDestroy(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for MPTokenIssuanceDestroy"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfMPTokenIssuanceID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT192::type::value_type + getMPTokenIssuanceID() const + { + return this->tx_->at(sfMPTokenIssuanceID); + } +}; + +/** + * @brief Builder for MPTokenIssuanceDestroy transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class MPTokenIssuanceDestroyBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new MPTokenIssuanceDestroyBuilder with required fields. + * @param account The account initiating the transaction. + * @param mPTokenIssuanceID The sfMPTokenIssuanceID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + MPTokenIssuanceDestroyBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& mPTokenIssuanceID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttMPTOKEN_ISSUANCE_DESTROY, account, sequence, fee) + { + setMPTokenIssuanceID(mPTokenIssuanceID); + } + + /** + * @brief Construct a MPTokenIssuanceDestroyBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + MPTokenIssuanceDestroyBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttMPTOKEN_ISSUANCE_DESTROY) + { + throw std::runtime_error("Invalid transaction type for MPTokenIssuanceDestroyBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfMPTokenIssuanceID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceDestroyBuilder& + setMPTokenIssuanceID(std::decay_t const& value) + { + object_[sfMPTokenIssuanceID] = value; + return *this; + } + + /** + * @brief Build and return the MPTokenIssuanceDestroy wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + MPTokenIssuanceDestroy + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return MPTokenIssuanceDestroy{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceSet.h b/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceSet.h new file mode 100644 index 0000000000..429b252e95 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/MPTokenIssuanceSet.h @@ -0,0 +1,314 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class MPTokenIssuanceSetBuilder; + +/** + * @brief Transaction: MPTokenIssuanceSet + * + * Type: ttMPTOKEN_ISSUANCE_SET (56) + * Delegable: Delegation::delegable + * Amendment: featureMPTokensV1 + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use MPTokenIssuanceSetBuilder to construct new transactions. + */ +class MPTokenIssuanceSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttMPTOKEN_ISSUANCE_SET; + + /** + * @brief Construct a MPTokenIssuanceSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit MPTokenIssuanceSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for MPTokenIssuanceSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfMPTokenIssuanceID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT192::type::value_type + getMPTokenIssuanceID() const + { + return this->tx_->at(sfMPTokenIssuanceID); + } + + /** + * @brief Get sfHolder (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getHolder() const + { + if (hasHolder()) + { + return this->tx_->at(sfHolder); + } + return std::nullopt; + } + + /** + * @brief Check if sfHolder is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasHolder() const + { + return this->tx_->isFieldPresent(sfHolder); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } + + /** + * @brief Get sfMPTokenMetadata (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMPTokenMetadata() const + { + if (hasMPTokenMetadata()) + { + return this->tx_->at(sfMPTokenMetadata); + } + return std::nullopt; + } + + /** + * @brief Check if sfMPTokenMetadata is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMPTokenMetadata() const + { + return this->tx_->isFieldPresent(sfMPTokenMetadata); + } + + /** + * @brief Get sfTransferFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferFee() const + { + if (hasTransferFee()) + { + return this->tx_->at(sfTransferFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfTransferFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferFee() const + { + return this->tx_->isFieldPresent(sfTransferFee); + } + + /** + * @brief Get sfMutableFlags (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMutableFlags() const + { + if (hasMutableFlags()) + { + return this->tx_->at(sfMutableFlags); + } + return std::nullopt; + } + + /** + * @brief Check if sfMutableFlags is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMutableFlags() const + { + return this->tx_->isFieldPresent(sfMutableFlags); + } +}; + +/** + * @brief Builder for MPTokenIssuanceSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class MPTokenIssuanceSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new MPTokenIssuanceSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param mPTokenIssuanceID The sfMPTokenIssuanceID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + MPTokenIssuanceSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& mPTokenIssuanceID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttMPTOKEN_ISSUANCE_SET, account, sequence, fee) + { + setMPTokenIssuanceID(mPTokenIssuanceID); + } + + /** + * @brief Construct a MPTokenIssuanceSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + MPTokenIssuanceSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttMPTOKEN_ISSUANCE_SET) + { + throw std::runtime_error("Invalid transaction type for MPTokenIssuanceSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfMPTokenIssuanceID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceSetBuilder& + setMPTokenIssuanceID(std::decay_t const& value) + { + object_[sfMPTokenIssuanceID] = value; + return *this; + } + + /** + * @brief Set sfHolder (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceSetBuilder& + setHolder(std::decay_t const& value) + { + object_[sfHolder] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceSetBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfMPTokenMetadata (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceSetBuilder& + setMPTokenMetadata(std::decay_t const& value) + { + object_[sfMPTokenMetadata] = value; + return *this; + } + + /** + * @brief Set sfTransferFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceSetBuilder& + setTransferFee(std::decay_t const& value) + { + object_[sfTransferFee] = value; + return *this; + } + + /** + * @brief Set sfMutableFlags (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + MPTokenIssuanceSetBuilder& + setMutableFlags(std::decay_t const& value) + { + object_[sfMutableFlags] = value; + return *this; + } + + /** + * @brief Build and return the MPTokenIssuanceSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + MPTokenIssuanceSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return MPTokenIssuanceSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/NFTokenAcceptOffer.h b/include/xrpl/protocol_autogen/transactions/NFTokenAcceptOffer.h new file mode 100644 index 0000000000..53ae614ee4 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/NFTokenAcceptOffer.h @@ -0,0 +1,216 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class NFTokenAcceptOfferBuilder; + +/** + * @brief Transaction: NFTokenAcceptOffer + * + * Type: ttNFTOKEN_ACCEPT_OFFER (29) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use NFTokenAcceptOfferBuilder to construct new transactions. + */ +class NFTokenAcceptOffer : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttNFTOKEN_ACCEPT_OFFER; + + /** + * @brief Construct a NFTokenAcceptOffer transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit NFTokenAcceptOffer(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for NFTokenAcceptOffer"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfNFTokenBuyOffer (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNFTokenBuyOffer() const + { + if (hasNFTokenBuyOffer()) + { + return this->tx_->at(sfNFTokenBuyOffer); + } + return std::nullopt; + } + + /** + * @brief Check if sfNFTokenBuyOffer is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNFTokenBuyOffer() const + { + return this->tx_->isFieldPresent(sfNFTokenBuyOffer); + } + + /** + * @brief Get sfNFTokenSellOffer (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNFTokenSellOffer() const + { + if (hasNFTokenSellOffer()) + { + return this->tx_->at(sfNFTokenSellOffer); + } + return std::nullopt; + } + + /** + * @brief Check if sfNFTokenSellOffer is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNFTokenSellOffer() const + { + return this->tx_->isFieldPresent(sfNFTokenSellOffer); + } + + /** + * @brief Get sfNFTokenBrokerFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getNFTokenBrokerFee() const + { + if (hasNFTokenBrokerFee()) + { + return this->tx_->at(sfNFTokenBrokerFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfNFTokenBrokerFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasNFTokenBrokerFee() const + { + return this->tx_->isFieldPresent(sfNFTokenBrokerFee); + } +}; + +/** + * @brief Builder for NFTokenAcceptOffer transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class NFTokenAcceptOfferBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenAcceptOfferBuilder 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. + */ + NFTokenAcceptOfferBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttNFTOKEN_ACCEPT_OFFER, account, sequence, fee) + { + } + + /** + * @brief Construct a NFTokenAcceptOfferBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + NFTokenAcceptOfferBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttNFTOKEN_ACCEPT_OFFER) + { + throw std::runtime_error("Invalid transaction type for NFTokenAcceptOfferBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfNFTokenBuyOffer (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenAcceptOfferBuilder& + setNFTokenBuyOffer(std::decay_t const& value) + { + object_[sfNFTokenBuyOffer] = value; + return *this; + } + + /** + * @brief Set sfNFTokenSellOffer (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenAcceptOfferBuilder& + setNFTokenSellOffer(std::decay_t const& value) + { + object_[sfNFTokenSellOffer] = value; + return *this; + } + + /** + * @brief Set sfNFTokenBrokerFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenAcceptOfferBuilder& + setNFTokenBrokerFee(std::decay_t const& value) + { + object_[sfNFTokenBrokerFee] = value; + return *this; + } + + /** + * @brief Build and return the NFTokenAcceptOffer wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + NFTokenAcceptOffer + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return NFTokenAcceptOffer{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/NFTokenBurn.h b/include/xrpl/protocol_autogen/transactions/NFTokenBurn.h new file mode 100644 index 0000000000..123418d00a --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/NFTokenBurn.h @@ -0,0 +1,166 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class NFTokenBurnBuilder; + +/** + * @brief Transaction: NFTokenBurn + * + * Type: ttNFTOKEN_BURN (26) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: changeNFTCounts + * + * Immutable wrapper around STTx providing type-safe field access. + * Use NFTokenBurnBuilder to construct new transactions. + */ +class NFTokenBurn : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttNFTOKEN_BURN; + + /** + * @brief Construct a NFTokenBurn transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit NFTokenBurn(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for NFTokenBurn"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfNFTokenID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getNFTokenID() const + { + return this->tx_->at(sfNFTokenID); + } + + /** + * @brief Get sfOwner (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwner() const + { + if (hasOwner()) + { + return this->tx_->at(sfOwner); + } + return std::nullopt; + } + + /** + * @brief Check if sfOwner is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwner() const + { + return this->tx_->isFieldPresent(sfOwner); + } +}; + +/** + * @brief Builder for NFTokenBurn transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class NFTokenBurnBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenBurnBuilder with required fields. + * @param account The account initiating the transaction. + * @param nFTokenID The sfNFTokenID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + NFTokenBurnBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& nFTokenID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttNFTOKEN_BURN, account, sequence, fee) + { + setNFTokenID(nFTokenID); + } + + /** + * @brief Construct a NFTokenBurnBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + NFTokenBurnBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttNFTOKEN_BURN) + { + throw std::runtime_error("Invalid transaction type for NFTokenBurnBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfNFTokenID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenBurnBuilder& + setNFTokenID(std::decay_t const& value) + { + object_[sfNFTokenID] = value; + return *this; + } + + /** + * @brief Set sfOwner (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenBurnBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Build and return the NFTokenBurn wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + NFTokenBurn + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return NFTokenBurn{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/NFTokenCancelOffer.h b/include/xrpl/protocol_autogen/transactions/NFTokenCancelOffer.h new file mode 100644 index 0000000000..5fbbeca96c --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/NFTokenCancelOffer.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class NFTokenCancelOfferBuilder; + +/** + * @brief Transaction: NFTokenCancelOffer + * + * Type: ttNFTOKEN_CANCEL_OFFER (28) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use NFTokenCancelOfferBuilder to construct new transactions. + */ +class NFTokenCancelOffer : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttNFTOKEN_CANCEL_OFFER; + + /** + * @brief Construct a NFTokenCancelOffer transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit NFTokenCancelOffer(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for NFTokenCancelOffer"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfNFTokenOffers (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VECTOR256::type::value_type + getNFTokenOffers() const + { + return this->tx_->at(sfNFTokenOffers); + } +}; + +/** + * @brief Builder for NFTokenCancelOffer transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class NFTokenCancelOfferBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenCancelOfferBuilder with required fields. + * @param account The account initiating the transaction. + * @param nFTokenOffers The sfNFTokenOffers field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + NFTokenCancelOfferBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& nFTokenOffers, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttNFTOKEN_CANCEL_OFFER, account, sequence, fee) + { + setNFTokenOffers(nFTokenOffers); + } + + /** + * @brief Construct a NFTokenCancelOfferBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + NFTokenCancelOfferBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttNFTOKEN_CANCEL_OFFER) + { + throw std::runtime_error("Invalid transaction type for NFTokenCancelOfferBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfNFTokenOffers (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenCancelOfferBuilder& + setNFTokenOffers(std::decay_t const& value) + { + object_[sfNFTokenOffers] = value; + return *this; + } + + /** + * @brief Build and return the NFTokenCancelOffer wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + NFTokenCancelOffer + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return NFTokenCancelOffer{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/NFTokenCreateOffer.h b/include/xrpl/protocol_autogen/transactions/NFTokenCreateOffer.h new file mode 100644 index 0000000000..e820272f83 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/NFTokenCreateOffer.h @@ -0,0 +1,264 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class NFTokenCreateOfferBuilder; + +/** + * @brief Transaction: NFTokenCreateOffer + * + * Type: ttNFTOKEN_CREATE_OFFER (27) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use NFTokenCreateOfferBuilder to construct new transactions. + */ +class NFTokenCreateOffer : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttNFTOKEN_CREATE_OFFER; + + /** + * @brief Construct a NFTokenCreateOffer transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit NFTokenCreateOffer(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for NFTokenCreateOffer"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfNFTokenID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getNFTokenID() const + { + return this->tx_->at(sfNFTokenID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfDestination (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Get sfOwner (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwner() const + { + if (hasOwner()) + { + return this->tx_->at(sfOwner); + } + return std::nullopt; + } + + /** + * @brief Check if sfOwner is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwner() const + { + return this->tx_->isFieldPresent(sfOwner); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + { + return this->tx_->at(sfExpiration); + } + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->tx_->isFieldPresent(sfExpiration); + } +}; + +/** + * @brief Builder for NFTokenCreateOffer transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class NFTokenCreateOfferBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenCreateOfferBuilder with required fields. + * @param account The account initiating the transaction. + * @param nFTokenID The sfNFTokenID field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + NFTokenCreateOfferBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& nFTokenID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttNFTOKEN_CREATE_OFFER, account, sequence, fee) + { + setNFTokenID(nFTokenID); + setAmount(amount); + } + + /** + * @brief Construct a NFTokenCreateOfferBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + NFTokenCreateOfferBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttNFTOKEN_CREATE_OFFER) + { + throw std::runtime_error("Invalid transaction type for NFTokenCreateOfferBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfNFTokenID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenCreateOfferBuilder& + setNFTokenID(std::decay_t const& value) + { + object_[sfNFTokenID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenCreateOfferBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenCreateOfferBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfOwner (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenCreateOfferBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenCreateOfferBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Build and return the NFTokenCreateOffer wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + NFTokenCreateOffer + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return NFTokenCreateOffer{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/NFTokenMint.h b/include/xrpl/protocol_autogen/transactions/NFTokenMint.h new file mode 100644 index 0000000000..9854147570 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/NFTokenMint.h @@ -0,0 +1,351 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class NFTokenMintBuilder; + +/** + * @brief Transaction: NFTokenMint + * + * Type: ttNFTOKEN_MINT (25) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: changeNFTCounts + * + * Immutable wrapper around STTx providing type-safe field access. + * Use NFTokenMintBuilder to construct new transactions. + */ +class NFTokenMint : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttNFTOKEN_MINT; + + /** + * @brief Construct a NFTokenMint transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit NFTokenMint(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for NFTokenMint"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfNFTokenTaxon (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getNFTokenTaxon() const + { + return this->tx_->at(sfNFTokenTaxon); + } + + /** + * @brief Get sfTransferFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getTransferFee() const + { + if (hasTransferFee()) + { + return this->tx_->at(sfTransferFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfTransferFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasTransferFee() const + { + return this->tx_->isFieldPresent(sfTransferFee); + } + + /** + * @brief Get sfIssuer (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getIssuer() const + { + if (hasIssuer()) + { + return this->tx_->at(sfIssuer); + } + return std::nullopt; + } + + /** + * @brief Check if sfIssuer is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasIssuer() const + { + return this->tx_->isFieldPresent(sfIssuer); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + { + return this->tx_->at(sfURI); + } + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->tx_->isFieldPresent(sfURI); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } + + /** + * @brief Get sfDestination (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + { + return this->tx_->at(sfExpiration); + } + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->tx_->isFieldPresent(sfExpiration); + } +}; + +/** + * @brief Builder for NFTokenMint transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class NFTokenMintBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenMintBuilder with required fields. + * @param account The account initiating the transaction. + * @param nFTokenTaxon The sfNFTokenTaxon field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + NFTokenMintBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& nFTokenTaxon, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttNFTOKEN_MINT, account, sequence, fee) + { + setNFTokenTaxon(nFTokenTaxon); + } + + /** + * @brief Construct a NFTokenMintBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + NFTokenMintBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttNFTOKEN_MINT) + { + throw std::runtime_error("Invalid transaction type for NFTokenMintBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfNFTokenTaxon (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setNFTokenTaxon(std::decay_t const& value) + { + object_[sfNFTokenTaxon] = value; + return *this; + } + + /** + * @brief Set sfTransferFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setTransferFee(std::decay_t const& value) + { + object_[sfTransferFee] = value; + return *this; + } + + /** + * @brief Set sfIssuer (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setIssuer(std::decay_t const& value) + { + object_[sfIssuer] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenMintBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Build and return the NFTokenMint wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + NFTokenMint + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return NFTokenMint{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/NFTokenModify.h b/include/xrpl/protocol_autogen/transactions/NFTokenModify.h new file mode 100644 index 0000000000..6f9b75532c --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/NFTokenModify.h @@ -0,0 +1,203 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class NFTokenModifyBuilder; + +/** + * @brief Transaction: NFTokenModify + * + * Type: ttNFTOKEN_MODIFY (61) + * Delegable: Delegation::delegable + * Amendment: featureDynamicNFT + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use NFTokenModifyBuilder to construct new transactions. + */ +class NFTokenModify : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttNFTOKEN_MODIFY; + + /** + * @brief Construct a NFTokenModify transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit NFTokenModify(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for NFTokenModify"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfNFTokenID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getNFTokenID() const + { + return this->tx_->at(sfNFTokenID); + } + + /** + * @brief Get sfOwner (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOwner() const + { + if (hasOwner()) + { + return this->tx_->at(sfOwner); + } + return std::nullopt; + } + + /** + * @brief Check if sfOwner is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwner() const + { + return this->tx_->isFieldPresent(sfOwner); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + { + return this->tx_->at(sfURI); + } + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->tx_->isFieldPresent(sfURI); + } +}; + +/** + * @brief Builder for NFTokenModify transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class NFTokenModifyBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new NFTokenModifyBuilder with required fields. + * @param account The account initiating the transaction. + * @param nFTokenID The sfNFTokenID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + NFTokenModifyBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& nFTokenID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttNFTOKEN_MODIFY, account, sequence, fee) + { + setNFTokenID(nFTokenID); + } + + /** + * @brief Construct a NFTokenModifyBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + NFTokenModifyBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttNFTOKEN_MODIFY) + { + throw std::runtime_error("Invalid transaction type for NFTokenModifyBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfNFTokenID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + NFTokenModifyBuilder& + setNFTokenID(std::decay_t const& value) + { + object_[sfNFTokenID] = value; + return *this; + } + + /** + * @brief Set sfOwner (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenModifyBuilder& + setOwner(std::decay_t const& value) + { + object_[sfOwner] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + NFTokenModifyBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Build and return the NFTokenModify wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + NFTokenModify + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return NFTokenModify{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/OfferCancel.h b/include/xrpl/protocol_autogen/transactions/OfferCancel.h new file mode 100644 index 0000000000..ed2c761c0e --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/OfferCancel.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class OfferCancelBuilder; + +/** + * @brief Transaction: OfferCancel + * + * Type: ttOFFER_CANCEL (8) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use OfferCancelBuilder to construct new transactions. + */ +class OfferCancel : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttOFFER_CANCEL; + + /** + * @brief Construct a OfferCancel transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit OfferCancel(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for OfferCancel"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfOfferSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getOfferSequence() const + { + return this->tx_->at(sfOfferSequence); + } +}; + +/** + * @brief Builder for OfferCancel transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class OfferCancelBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new OfferCancelBuilder with required fields. + * @param account The account initiating the transaction. + * @param offerSequence The sfOfferSequence field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + OfferCancelBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& offerSequence, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttOFFER_CANCEL, account, sequence, fee) + { + setOfferSequence(offerSequence); + } + + /** + * @brief Construct a OfferCancelBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + OfferCancelBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttOFFER_CANCEL) + { + throw std::runtime_error("Invalid transaction type for OfferCancelBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfOfferSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferCancelBuilder& + setOfferSequence(std::decay_t const& value) + { + object_[sfOfferSequence] = value; + return *this; + } + + /** + * @brief Build and return the OfferCancel wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + OfferCancel + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return OfferCancel{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/OfferCreate.h b/include/xrpl/protocol_autogen/transactions/OfferCreate.h new file mode 100644 index 0000000000..a0eff385f6 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/OfferCreate.h @@ -0,0 +1,264 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class OfferCreateBuilder; + +/** + * @brief Transaction: OfferCreate + * + * Type: ttOFFER_CREATE (7) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use OfferCreateBuilder to construct new transactions. + */ +class OfferCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttOFFER_CREATE; + + /** + * @brief Construct a OfferCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit OfferCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for OfferCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfTakerPays (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getTakerPays() const + { + return this->tx_->at(sfTakerPays); + } + + /** + * @brief Get sfTakerGets (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getTakerGets() const + { + return this->tx_->at(sfTakerGets); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + { + return this->tx_->at(sfExpiration); + } + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->tx_->isFieldPresent(sfExpiration); + } + + /** + * @brief Get sfOfferSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getOfferSequence() const + { + if (hasOfferSequence()) + { + return this->tx_->at(sfOfferSequence); + } + return std::nullopt; + } + + /** + * @brief Check if sfOfferSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOfferSequence() const + { + return this->tx_->isFieldPresent(sfOfferSequence); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } +}; + +/** + * @brief Builder for OfferCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class OfferCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new OfferCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param takerPays The sfTakerPays field value. + * @param takerGets The sfTakerGets field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + OfferCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& takerPays, std::decay_t const& takerGets, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttOFFER_CREATE, account, sequence, fee) + { + setTakerPays(takerPays); + setTakerGets(takerGets); + } + + /** + * @brief Construct a OfferCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + OfferCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttOFFER_CREATE) + { + throw std::runtime_error("Invalid transaction type for OfferCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfTakerPays (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferCreateBuilder& + setTakerPays(std::decay_t const& value) + { + object_[sfTakerPays] = value; + return *this; + } + + /** + * @brief Set sfTakerGets (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OfferCreateBuilder& + setTakerGets(std::decay_t const& value) + { + object_[sfTakerGets] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OfferCreateBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Set sfOfferSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OfferCreateBuilder& + setOfferSequence(std::decay_t const& value) + { + object_[sfOfferSequence] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OfferCreateBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Build and return the OfferCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + OfferCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return OfferCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/OracleDelete.h b/include/xrpl/protocol_autogen/transactions/OracleDelete.h new file mode 100644 index 0000000000..6cafd2b6de --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/OracleDelete.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class OracleDeleteBuilder; + +/** + * @brief Transaction: OracleDelete + * + * Type: ttORACLE_DELETE (52) + * Delegable: Delegation::delegable + * Amendment: featurePriceOracle + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use OracleDeleteBuilder to construct new transactions. + */ +class OracleDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttORACLE_DELETE; + + /** + * @brief Construct a OracleDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit OracleDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for OracleDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfOracleDocumentID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getOracleDocumentID() const + { + return this->tx_->at(sfOracleDocumentID); + } +}; + +/** + * @brief Builder for OracleDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class OracleDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new OracleDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param oracleDocumentID The sfOracleDocumentID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + OracleDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& oracleDocumentID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttORACLE_DELETE, account, sequence, fee) + { + setOracleDocumentID(oracleDocumentID); + } + + /** + * @brief Construct a OracleDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + OracleDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttORACLE_DELETE) + { + throw std::runtime_error("Invalid transaction type for OracleDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfOracleDocumentID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleDeleteBuilder& + setOracleDocumentID(std::decay_t const& value) + { + object_[sfOracleDocumentID] = value; + return *this; + } + + /** + * @brief Build and return the OracleDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + OracleDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return OracleDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/OracleSet.h b/include/xrpl/protocol_autogen/transactions/OracleSet.h new file mode 100644 index 0000000000..8dd0d88865 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/OracleSet.h @@ -0,0 +1,288 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class OracleSetBuilder; + +/** + * @brief Transaction: OracleSet + * + * Type: ttORACLE_SET (51) + * Delegable: Delegation::delegable + * Amendment: featurePriceOracle + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use OracleSetBuilder to construct new transactions. + */ +class OracleSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttORACLE_SET; + + /** + * @brief Construct a OracleSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit OracleSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for OracleSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfOracleDocumentID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getOracleDocumentID() const + { + return this->tx_->at(sfOracleDocumentID); + } + + /** + * @brief Get sfProvider (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getProvider() const + { + if (hasProvider()) + { + return this->tx_->at(sfProvider); + } + return std::nullopt; + } + + /** + * @brief Check if sfProvider is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasProvider() const + { + return this->tx_->isFieldPresent(sfProvider); + } + + /** + * @brief Get sfURI (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getURI() const + { + if (hasURI()) + { + return this->tx_->at(sfURI); + } + return std::nullopt; + } + + /** + * @brief Check if sfURI is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasURI() const + { + return this->tx_->isFieldPresent(sfURI); + } + + /** + * @brief Get sfAssetClass (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetClass() const + { + if (hasAssetClass()) + { + return this->tx_->at(sfAssetClass); + } + return std::nullopt; + } + + /** + * @brief Check if sfAssetClass is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetClass() const + { + return this->tx_->isFieldPresent(sfAssetClass); + } + + /** + * @brief Get sfLastUpdateTime (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getLastUpdateTime() const + { + return this->tx_->at(sfLastUpdateTime); + } + /** + * @brief Get sfPriceDataSeries (soeREQUIRED) + * @note This is an untyped field. + * @return The field value. + */ + [[nodiscard]] + STArray const& + getPriceDataSeries() const + { + return this->tx_->getFieldArray(sfPriceDataSeries); + } +}; + +/** + * @brief Builder for OracleSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class OracleSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new OracleSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param oracleDocumentID The sfOracleDocumentID field value. + * @param lastUpdateTime The sfLastUpdateTime field value. + * @param priceDataSeries The sfPriceDataSeries field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + OracleSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& oracleDocumentID, std::decay_t const& lastUpdateTime, STArray const& priceDataSeries, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttORACLE_SET, account, sequence, fee) + { + setOracleDocumentID(oracleDocumentID); + setLastUpdateTime(lastUpdateTime); + setPriceDataSeries(priceDataSeries); + } + + /** + * @brief Construct a OracleSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + OracleSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttORACLE_SET) + { + throw std::runtime_error("Invalid transaction type for OracleSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfOracleDocumentID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleSetBuilder& + setOracleDocumentID(std::decay_t const& value) + { + object_[sfOracleDocumentID] = value; + return *this; + } + + /** + * @brief Set sfProvider (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OracleSetBuilder& + setProvider(std::decay_t const& value) + { + object_[sfProvider] = value; + return *this; + } + + /** + * @brief Set sfURI (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OracleSetBuilder& + setURI(std::decay_t const& value) + { + object_[sfURI] = value; + return *this; + } + + /** + * @brief Set sfAssetClass (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + OracleSetBuilder& + setAssetClass(std::decay_t const& value) + { + object_[sfAssetClass] = value; + return *this; + } + + /** + * @brief Set sfLastUpdateTime (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleSetBuilder& + setLastUpdateTime(std::decay_t const& value) + { + object_[sfLastUpdateTime] = value; + return *this; + } + + /** + * @brief Set sfPriceDataSeries (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + OracleSetBuilder& + setPriceDataSeries(STArray const& value) + { + object_.setFieldArray(sfPriceDataSeries, value); + return *this; + } + + /** + * @brief Build and return the OracleSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + OracleSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return OracleSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/Payment.h b/include/xrpl/protocol_autogen/transactions/Payment.h new file mode 100644 index 0000000000..877286f90e --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/Payment.h @@ -0,0 +1,416 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class PaymentBuilder; + +/** + * @brief Transaction: Payment + * + * Type: ttPAYMENT (0) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: createAcct + * + * Immutable wrapper around STTx providing type-safe field access. + * Use PaymentBuilder to construct new transactions. + */ +class Payment : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttPAYMENT; + + /** + * @brief Construct a Payment transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit Payment(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for Payment"); + } + } + + // Transaction-specific field getters + + /** + * @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) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfSendMax (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSendMax() const + { + if (hasSendMax()) + { + return this->tx_->at(sfSendMax); + } + return std::nullopt; + } + + /** + * @brief Check if sfSendMax is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSendMax() const + { + return this->tx_->isFieldPresent(sfSendMax); + } + /** + * @brief Get sfPaths (soeDEFAULT) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getPaths() const + { + if (this->tx_->isFieldPresent(sfPaths)) + return this->tx_->getFieldPathSet(sfPaths); + return std::nullopt; + } + + /** + * @brief Check if sfPaths is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPaths() const + { + return this->tx_->isFieldPresent(sfPaths); + } + + /** + * @brief Get sfInvoiceID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getInvoiceID() const + { + if (hasInvoiceID()) + { + return this->tx_->at(sfInvoiceID); + } + return std::nullopt; + } + + /** + * @brief Check if sfInvoiceID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasInvoiceID() const + { + return this->tx_->isFieldPresent(sfInvoiceID); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 sfDeliverMin (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDeliverMin() const + { + if (hasDeliverMin()) + { + return this->tx_->at(sfDeliverMin); + } + return std::nullopt; + } + + /** + * @brief Check if sfDeliverMin is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDeliverMin() const + { + return this->tx_->isFieldPresent(sfDeliverMin); + } + + /** + * @brief Get sfCredentialIDs (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCredentialIDs() const + { + if (hasCredentialIDs()) + { + return this->tx_->at(sfCredentialIDs); + } + return std::nullopt; + } + + /** + * @brief Check if sfCredentialIDs is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCredentialIDs() const + { + return this->tx_->isFieldPresent(sfCredentialIDs); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } +}; + +/** + * @brief Builder for Payment transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class PaymentBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new PaymentBuilder with required fields. + * @param account The account initiating the transaction. + * @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. + */ + PaymentBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& destination, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttPAYMENT, account, sequence, fee) + { + setDestination(destination); + setAmount(amount); + } + + /** + * @brief Construct a PaymentBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + PaymentBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttPAYMENT) + { + throw std::runtime_error("Invalid transaction type for PaymentBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfSendMax (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setSendMax(std::decay_t const& value) + { + object_[sfSendMax] = value; + return *this; + } + + /** + * @brief Set sfPaths (soeDEFAULT) + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setPaths(STPathSet const& value) + { + object_.setFieldPathSet(sfPaths, value); + return *this; + } + + /** + * @brief Set sfInvoiceID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setInvoiceID(std::decay_t const& value) + { + object_[sfInvoiceID] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfDeliverMin (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setDeliverMin(std::decay_t const& value) + { + object_[sfDeliverMin] = value; + return *this; + } + + /** + * @brief Set sfCredentialIDs (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setCredentialIDs(std::decay_t const& value) + { + object_[sfCredentialIDs] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Build and return the Payment wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + Payment + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return Payment{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/PaymentChannelClaim.h b/include/xrpl/protocol_autogen/transactions/PaymentChannelClaim.h new file mode 100644 index 0000000000..1e90c74aa1 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/PaymentChannelClaim.h @@ -0,0 +1,314 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class PaymentChannelClaimBuilder; + +/** + * @brief Transaction: PaymentChannelClaim + * + * Type: ttPAYCHAN_CLAIM (15) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use PaymentChannelClaimBuilder to construct new transactions. + */ +class PaymentChannelClaim : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttPAYCHAN_CLAIM; + + /** + * @brief Construct a PaymentChannelClaim transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit PaymentChannelClaim(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for PaymentChannelClaim"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfChannel (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getChannel() const + { + return this->tx_->at(sfChannel); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } + + /** + * @brief Get sfBalance (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBalance() const + { + if (hasBalance()) + { + return this->tx_->at(sfBalance); + } + return std::nullopt; + } + + /** + * @brief Check if sfBalance is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBalance() const + { + return this->tx_->isFieldPresent(sfBalance); + } + + /** + * @brief Get sfSignature (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getSignature() const + { + if (hasSignature()) + { + return this->tx_->at(sfSignature); + } + return std::nullopt; + } + + /** + * @brief Check if sfSignature is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSignature() const + { + return this->tx_->isFieldPresent(sfSignature); + } + + /** + * @brief Get sfPublicKey (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getPublicKey() const + { + if (hasPublicKey()) + { + return this->tx_->at(sfPublicKey); + } + return std::nullopt; + } + + /** + * @brief Check if sfPublicKey is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasPublicKey() const + { + return this->tx_->isFieldPresent(sfPublicKey); + } + + /** + * @brief Get sfCredentialIDs (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCredentialIDs() const + { + if (hasCredentialIDs()) + { + return this->tx_->at(sfCredentialIDs); + } + return std::nullopt; + } + + /** + * @brief Check if sfCredentialIDs is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCredentialIDs() const + { + return this->tx_->isFieldPresent(sfCredentialIDs); + } +}; + +/** + * @brief Builder for PaymentChannelClaim transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class PaymentChannelClaimBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new PaymentChannelClaimBuilder with required fields. + * @param account The account initiating the transaction. + * @param channel The sfChannel field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + PaymentChannelClaimBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& channel, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttPAYCHAN_CLAIM, account, sequence, fee) + { + setChannel(channel); + } + + /** + * @brief Construct a PaymentChannelClaimBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + PaymentChannelClaimBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttPAYCHAN_CLAIM) + { + throw std::runtime_error("Invalid transaction type for PaymentChannelClaimBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfChannel (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelClaimBuilder& + setChannel(std::decay_t const& value) + { + object_[sfChannel] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelClaimBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfBalance (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelClaimBuilder& + setBalance(std::decay_t const& value) + { + object_[sfBalance] = value; + return *this; + } + + /** + * @brief Set sfSignature (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelClaimBuilder& + setSignature(std::decay_t const& value) + { + object_[sfSignature] = value; + return *this; + } + + /** + * @brief Set sfPublicKey (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelClaimBuilder& + setPublicKey(std::decay_t const& value) + { + object_[sfPublicKey] = value; + return *this; + } + + /** + * @brief Set sfCredentialIDs (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelClaimBuilder& + setCredentialIDs(std::decay_t const& value) + { + object_[sfCredentialIDs] = value; + return *this; + } + + /** + * @brief Build and return the PaymentChannelClaim wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + PaymentChannelClaim + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return PaymentChannelClaim{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/PaymentChannelCreate.h b/include/xrpl/protocol_autogen/transactions/PaymentChannelCreate.h new file mode 100644 index 0000000000..4242046114 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/PaymentChannelCreate.h @@ -0,0 +1,275 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class PaymentChannelCreateBuilder; + +/** + * @brief Transaction: PaymentChannelCreate + * + * Type: ttPAYCHAN_CREATE (13) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use PaymentChannelCreateBuilder to construct new transactions. + */ +class PaymentChannelCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttPAYCHAN_CREATE; + + /** + * @brief Construct a PaymentChannelCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit PaymentChannelCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for PaymentChannelCreate"); + } + } + + // Transaction-specific field getters + + /** + * @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 sfSettleDelay (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSettleDelay() const + { + return this->tx_->at(sfSettleDelay); + } + + /** + * @brief Get sfPublicKey (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getPublicKey() const + { + return this->tx_->at(sfPublicKey); + } + + /** + * @brief Get sfCancelAfter (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getCancelAfter() const + { + if (hasCancelAfter()) + { + return this->tx_->at(sfCancelAfter); + } + return std::nullopt; + } + + /** + * @brief Check if sfCancelAfter is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasCancelAfter() const + { + return this->tx_->isFieldPresent(sfCancelAfter); + } + + /** + * @brief Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Builder for PaymentChannelCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class PaymentChannelCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new PaymentChannelCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param destination The sfDestination field value. + * @param amount The sfAmount field value. + * @param settleDelay The sfSettleDelay field value. + * @param publicKey The sfPublicKey field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + PaymentChannelCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& destination, std::decay_t const& amount, std::decay_t const& settleDelay, std::decay_t const& publicKey, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttPAYCHAN_CREATE, account, sequence, fee) + { + setDestination(destination); + setAmount(amount); + setSettleDelay(settleDelay); + setPublicKey(publicKey); + } + + /** + * @brief Construct a PaymentChannelCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + PaymentChannelCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttPAYCHAN_CREATE) + { + throw std::runtime_error("Invalid transaction type for PaymentChannelCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelCreateBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelCreateBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfSettleDelay (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelCreateBuilder& + setSettleDelay(std::decay_t const& value) + { + object_[sfSettleDelay] = value; + return *this; + } + + /** + * @brief Set sfPublicKey (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelCreateBuilder& + setPublicKey(std::decay_t const& value) + { + object_[sfPublicKey] = value; + return *this; + } + + /** + * @brief Set sfCancelAfter (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelCreateBuilder& + setCancelAfter(std::decay_t const& value) + { + object_[sfCancelAfter] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelCreateBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Build and return the PaymentChannelCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + PaymentChannelCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return PaymentChannelCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/PaymentChannelFund.h b/include/xrpl/protocol_autogen/transactions/PaymentChannelFund.h new file mode 100644 index 0000000000..2fecf21154 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/PaymentChannelFund.h @@ -0,0 +1,190 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class PaymentChannelFundBuilder; + +/** + * @brief Transaction: PaymentChannelFund + * + * Type: ttPAYCHAN_FUND (14) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use PaymentChannelFundBuilder to construct new transactions. + */ +class PaymentChannelFund : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttPAYCHAN_FUND; + + /** + * @brief Construct a PaymentChannelFund transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit PaymentChannelFund(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for PaymentChannelFund"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfChannel (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getChannel() const + { + return this->tx_->at(sfChannel); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfExpiration (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getExpiration() const + { + if (hasExpiration()) + { + return this->tx_->at(sfExpiration); + } + return std::nullopt; + } + + /** + * @brief Check if sfExpiration is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasExpiration() const + { + return this->tx_->isFieldPresent(sfExpiration); + } +}; + +/** + * @brief Builder for PaymentChannelFund transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class PaymentChannelFundBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new PaymentChannelFundBuilder with required fields. + * @param account The account initiating the transaction. + * @param channel The sfChannel field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + PaymentChannelFundBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& channel, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttPAYCHAN_FUND, account, sequence, fee) + { + setChannel(channel); + setAmount(amount); + } + + /** + * @brief Construct a PaymentChannelFundBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + PaymentChannelFundBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttPAYCHAN_FUND) + { + throw std::runtime_error("Invalid transaction type for PaymentChannelFundBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfChannel (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelFundBuilder& + setChannel(std::decay_t const& value) + { + object_[sfChannel] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PaymentChannelFundBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfExpiration (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PaymentChannelFundBuilder& + setExpiration(std::decay_t const& value) + { + object_[sfExpiration] = value; + return *this; + } + + /** + * @brief Build and return the PaymentChannelFund wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + PaymentChannelFund + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return PaymentChannelFund{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/PermissionedDomainDelete.h b/include/xrpl/protocol_autogen/transactions/PermissionedDomainDelete.h new file mode 100644 index 0000000000..c95e0f2e18 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/PermissionedDomainDelete.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class PermissionedDomainDeleteBuilder; + +/** + * @brief Transaction: PermissionedDomainDelete + * + * Type: ttPERMISSIONED_DOMAIN_DELETE (63) + * Delegable: Delegation::delegable + * Amendment: featurePermissionedDomains + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use PermissionedDomainDeleteBuilder to construct new transactions. + */ +class PermissionedDomainDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttPERMISSIONED_DOMAIN_DELETE; + + /** + * @brief Construct a PermissionedDomainDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit PermissionedDomainDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for PermissionedDomainDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfDomainID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getDomainID() const + { + return this->tx_->at(sfDomainID); + } +}; + +/** + * @brief Builder for PermissionedDomainDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class PermissionedDomainDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new PermissionedDomainDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param domainID The sfDomainID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + PermissionedDomainDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& domainID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttPERMISSIONED_DOMAIN_DELETE, account, sequence, fee) + { + setDomainID(domainID); + } + + /** + * @brief Construct a PermissionedDomainDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + PermissionedDomainDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttPERMISSIONED_DOMAIN_DELETE) + { + throw std::runtime_error("Invalid transaction type for PermissionedDomainDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDomainID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainDeleteBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Build and return the PermissionedDomainDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + PermissionedDomainDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return PermissionedDomainDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/PermissionedDomainSet.h b/include/xrpl/protocol_autogen/transactions/PermissionedDomainSet.h new file mode 100644 index 0000000000..38df7f4fc7 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/PermissionedDomainSet.h @@ -0,0 +1,166 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class PermissionedDomainSetBuilder; + +/** + * @brief Transaction: PermissionedDomainSet + * + * Type: ttPERMISSIONED_DOMAIN_SET (62) + * Delegable: Delegation::delegable + * Amendment: featurePermissionedDomains + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use PermissionedDomainSetBuilder to construct new transactions. + */ +class PermissionedDomainSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttPERMISSIONED_DOMAIN_SET; + + /** + * @brief Construct a PermissionedDomainSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit PermissionedDomainSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for PermissionedDomainSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } + /** + * @brief Get sfAcceptedCredentials (soeREQUIRED) + * @note This is an untyped field. + * @return The field value. + */ + [[nodiscard]] + STArray const& + getAcceptedCredentials() const + { + return this->tx_->getFieldArray(sfAcceptedCredentials); + } +}; + +/** + * @brief Builder for PermissionedDomainSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class PermissionedDomainSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new PermissionedDomainSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param acceptedCredentials The sfAcceptedCredentials field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + PermissionedDomainSetBuilder(SF_ACCOUNT::type::value_type account, + STArray const& acceptedCredentials, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttPERMISSIONED_DOMAIN_SET, account, sequence, fee) + { + setAcceptedCredentials(acceptedCredentials); + } + + /** + * @brief Construct a PermissionedDomainSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + PermissionedDomainSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttPERMISSIONED_DOMAIN_SET) + { + throw std::runtime_error("Invalid transaction type for PermissionedDomainSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainSetBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfAcceptedCredentials (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + PermissionedDomainSetBuilder& + setAcceptedCredentials(STArray const& value) + { + object_.setFieldArray(sfAcceptedCredentials, value); + return *this; + } + + /** + * @brief Build and return the PermissionedDomainSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + PermissionedDomainSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return PermissionedDomainSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/SetFee.h b/include/xrpl/protocol_autogen/transactions/SetFee.h new file mode 100644 index 0000000000..7bf73201b9 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/SetFee.h @@ -0,0 +1,401 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class SetFeeBuilder; + +/** + * @brief Transaction: SetFee + * + * Type: ttFEE (101) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use SetFeeBuilder to construct new transactions. + */ +class SetFee : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttFEE; + + /** + * @brief Construct a SetFee transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit SetFee(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for SetFee"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLedgerSequence (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLedgerSequence() const + { + if (hasLedgerSequence()) + { + return this->tx_->at(sfLedgerSequence); + } + return std::nullopt; + } + + /** + * @brief Check if sfLedgerSequence is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLedgerSequence() const + { + return this->tx_->isFieldPresent(sfLedgerSequence); + } + + /** + * @brief Get sfBaseFee (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBaseFee() const + { + if (hasBaseFee()) + { + return this->tx_->at(sfBaseFee); + } + return std::nullopt; + } + + /** + * @brief Check if sfBaseFee is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBaseFee() const + { + return this->tx_->isFieldPresent(sfBaseFee); + } + + /** + * @brief Get sfReferenceFeeUnits (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReferenceFeeUnits() const + { + if (hasReferenceFeeUnits()) + { + return this->tx_->at(sfReferenceFeeUnits); + } + return std::nullopt; + } + + /** + * @brief Check if sfReferenceFeeUnits is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReferenceFeeUnits() const + { + return this->tx_->isFieldPresent(sfReferenceFeeUnits); + } + + /** + * @brief Get sfReserveBase (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveBase() const + { + if (hasReserveBase()) + { + return this->tx_->at(sfReserveBase); + } + return std::nullopt; + } + + /** + * @brief Check if sfReserveBase is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveBase() const + { + return this->tx_->isFieldPresent(sfReserveBase); + } + + /** + * @brief Get sfReserveIncrement (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveIncrement() const + { + if (hasReserveIncrement()) + { + return this->tx_->at(sfReserveIncrement); + } + return std::nullopt; + } + + /** + * @brief Check if sfReserveIncrement is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveIncrement() const + { + return this->tx_->isFieldPresent(sfReserveIncrement); + } + + /** + * @brief Get sfBaseFeeDrops (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBaseFeeDrops() const + { + if (hasBaseFeeDrops()) + { + return this->tx_->at(sfBaseFeeDrops); + } + return std::nullopt; + } + + /** + * @brief Check if sfBaseFeeDrops is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBaseFeeDrops() const + { + return this->tx_->isFieldPresent(sfBaseFeeDrops); + } + + /** + * @brief Get sfReserveBaseDrops (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveBaseDrops() const + { + if (hasReserveBaseDrops()) + { + return this->tx_->at(sfReserveBaseDrops); + } + return std::nullopt; + } + + /** + * @brief Check if sfReserveBaseDrops is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveBaseDrops() const + { + return this->tx_->isFieldPresent(sfReserveBaseDrops); + } + + /** + * @brief Get sfReserveIncrementDrops (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getReserveIncrementDrops() const + { + if (hasReserveIncrementDrops()) + { + return this->tx_->at(sfReserveIncrementDrops); + } + return std::nullopt; + } + + /** + * @brief Check if sfReserveIncrementDrops is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasReserveIncrementDrops() const + { + return this->tx_->isFieldPresent(sfReserveIncrementDrops); + } +}; + +/** + * @brief Builder for SetFee transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class SetFeeBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new SetFeeBuilder 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. + */ + SetFeeBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttFEE, account, sequence, fee) + { + } + + /** + * @brief Construct a SetFeeBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + SetFeeBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttFEE) + { + throw std::runtime_error("Invalid transaction type for SetFeeBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLedgerSequence (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setLedgerSequence(std::decay_t const& value) + { + object_[sfLedgerSequence] = value; + return *this; + } + + /** + * @brief Set sfBaseFee (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setBaseFee(std::decay_t const& value) + { + object_[sfBaseFee] = value; + return *this; + } + + /** + * @brief Set sfReferenceFeeUnits (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setReferenceFeeUnits(std::decay_t const& value) + { + object_[sfReferenceFeeUnits] = value; + return *this; + } + + /** + * @brief Set sfReserveBase (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setReserveBase(std::decay_t const& value) + { + object_[sfReserveBase] = value; + return *this; + } + + /** + * @brief Set sfReserveIncrement (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setReserveIncrement(std::decay_t const& value) + { + object_[sfReserveIncrement] = value; + return *this; + } + + /** + * @brief Set sfBaseFeeDrops (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setBaseFeeDrops(std::decay_t const& value) + { + object_[sfBaseFeeDrops] = value; + return *this; + } + + /** + * @brief Set sfReserveBaseDrops (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setReserveBaseDrops(std::decay_t const& value) + { + object_[sfReserveBaseDrops] = value; + return *this; + } + + /** + * @brief Set sfReserveIncrementDrops (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetFeeBuilder& + setReserveIncrementDrops(std::decay_t const& value) + { + object_[sfReserveIncrementDrops] = value; + return *this; + } + + /** + * @brief Build and return the SetFee wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + SetFee + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return SetFee{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/SetRegularKey.h b/include/xrpl/protocol_autogen/transactions/SetRegularKey.h new file mode 100644 index 0000000000..3d70d092c5 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/SetRegularKey.h @@ -0,0 +1,142 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class SetRegularKeyBuilder; + +/** + * @brief Transaction: SetRegularKey + * + * Type: ttREGULAR_KEY_SET (5) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use SetRegularKeyBuilder to construct new transactions. + */ +class SetRegularKey : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttREGULAR_KEY_SET; + + /** + * @brief Construct a SetRegularKey transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit SetRegularKey(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for SetRegularKey"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfRegularKey (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getRegularKey() const + { + if (hasRegularKey()) + { + return this->tx_->at(sfRegularKey); + } + return std::nullopt; + } + + /** + * @brief Check if sfRegularKey is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasRegularKey() const + { + return this->tx_->isFieldPresent(sfRegularKey); + } +}; + +/** + * @brief Builder for SetRegularKey transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class SetRegularKeyBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new SetRegularKeyBuilder 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. + */ + SetRegularKeyBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttREGULAR_KEY_SET, account, sequence, fee) + { + } + + /** + * @brief Construct a SetRegularKeyBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + SetRegularKeyBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttREGULAR_KEY_SET) + { + throw std::runtime_error("Invalid transaction type for SetRegularKeyBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfRegularKey (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SetRegularKeyBuilder& + setRegularKey(std::decay_t const& value) + { + object_[sfRegularKey] = value; + return *this; + } + + /** + * @brief Build and return the SetRegularKey wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + SetRegularKey + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return SetRegularKey{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/SignerListSet.h b/include/xrpl/protocol_autogen/transactions/SignerListSet.h new file mode 100644 index 0000000000..ec5330a9cb --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/SignerListSet.h @@ -0,0 +1,164 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class SignerListSetBuilder; + +/** + * @brief Transaction: SignerListSet + * + * Type: ttSIGNER_LIST_SET (12) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use SignerListSetBuilder to construct new transactions. + */ +class SignerListSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttSIGNER_LIST_SET; + + /** + * @brief Construct a SignerListSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit SignerListSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for SignerListSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfSignerQuorum (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getSignerQuorum() const + { + return this->tx_->at(sfSignerQuorum); + } + /** + * @brief Get sfSignerEntries (soeOPTIONAL) + * @note This is an untyped field. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + std::optional> + getSignerEntries() const + { + if (this->tx_->isFieldPresent(sfSignerEntries)) + return this->tx_->getFieldArray(sfSignerEntries); + return std::nullopt; + } + + /** + * @brief Check if sfSignerEntries is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasSignerEntries() const + { + return this->tx_->isFieldPresent(sfSignerEntries); + } +}; + +/** + * @brief Builder for SignerListSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class SignerListSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new SignerListSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param signerQuorum The sfSignerQuorum field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + SignerListSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& signerQuorum, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttSIGNER_LIST_SET, account, sequence, fee) + { + setSignerQuorum(signerQuorum); + } + + /** + * @brief Construct a SignerListSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + SignerListSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttSIGNER_LIST_SET) + { + throw std::runtime_error("Invalid transaction type for SignerListSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfSignerQuorum (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + SignerListSetBuilder& + setSignerQuorum(std::decay_t const& value) + { + object_[sfSignerQuorum] = value; + return *this; + } + + /** + * @brief Set sfSignerEntries (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + SignerListSetBuilder& + setSignerEntries(STArray const& value) + { + object_.setFieldArray(sfSignerEntries, value); + return *this; + } + + /** + * @brief Build and return the SignerListSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + SignerListSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return SignerListSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/TicketCreate.h b/include/xrpl/protocol_autogen/transactions/TicketCreate.h new file mode 100644 index 0000000000..842ae93111 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/TicketCreate.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class TicketCreateBuilder; + +/** + * @brief Transaction: TicketCreate + * + * Type: ttTICKET_CREATE (10) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use TicketCreateBuilder to construct new transactions. + */ +class TicketCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttTICKET_CREATE; + + /** + * @brief Construct a TicketCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit TicketCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for TicketCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfTicketCount (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getTicketCount() const + { + return this->tx_->at(sfTicketCount); + } +}; + +/** + * @brief Builder for TicketCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class TicketCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new TicketCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param ticketCount The sfTicketCount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + TicketCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& ticketCount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttTICKET_CREATE, account, sequence, fee) + { + setTicketCount(ticketCount); + } + + /** + * @brief Construct a TicketCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + TicketCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttTICKET_CREATE) + { + throw std::runtime_error("Invalid transaction type for TicketCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfTicketCount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + TicketCreateBuilder& + setTicketCount(std::decay_t const& value) + { + object_[sfTicketCount] = value; + return *this; + } + + /** + * @brief Build and return the TicketCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + TicketCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return TicketCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/TrustSet.h b/include/xrpl/protocol_autogen/transactions/TrustSet.h new file mode 100644 index 0000000000..5623311b92 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/TrustSet.h @@ -0,0 +1,216 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class TrustSetBuilder; + +/** + * @brief Transaction: TrustSet + * + * Type: ttTRUST_SET (20) + * Delegable: Delegation::delegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use TrustSetBuilder to construct new transactions. + */ +class TrustSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttTRUST_SET; + + /** + * @brief Construct a TrustSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit TrustSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for TrustSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfLimitAmount (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getLimitAmount() const + { + if (hasLimitAmount()) + { + return this->tx_->at(sfLimitAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfLimitAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasLimitAmount() const + { + return this->tx_->isFieldPresent(sfLimitAmount); + } + + /** + * @brief Get sfQualityIn (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getQualityIn() const + { + if (hasQualityIn()) + { + return this->tx_->at(sfQualityIn); + } + return std::nullopt; + } + + /** + * @brief Check if sfQualityIn is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasQualityIn() const + { + return this->tx_->isFieldPresent(sfQualityIn); + } + + /** + * @brief Get sfQualityOut (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getQualityOut() const + { + if (hasQualityOut()) + { + return this->tx_->at(sfQualityOut); + } + return std::nullopt; + } + + /** + * @brief Check if sfQualityOut is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasQualityOut() const + { + return this->tx_->isFieldPresent(sfQualityOut); + } +}; + +/** + * @brief Builder for TrustSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class TrustSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new TrustSetBuilder 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. + */ + TrustSetBuilder(SF_ACCOUNT::type::value_type account, + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttTRUST_SET, account, sequence, fee) + { + } + + /** + * @brief Construct a TrustSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + TrustSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttTRUST_SET) + { + throw std::runtime_error("Invalid transaction type for TrustSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLimitAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + TrustSetBuilder& + setLimitAmount(std::decay_t const& value) + { + object_[sfLimitAmount] = value; + return *this; + } + + /** + * @brief Set sfQualityIn (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + TrustSetBuilder& + setQualityIn(std::decay_t const& value) + { + object_[sfQualityIn] = value; + return *this; + } + + /** + * @brief Set sfQualityOut (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + TrustSetBuilder& + setQualityOut(std::decay_t const& value) + { + object_[sfQualityOut] = value; + return *this; + } + + /** + * @brief Build and return the TrustSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + TrustSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return TrustSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/UNLModify.h b/include/xrpl/protocol_autogen/transactions/UNLModify.h new file mode 100644 index 0000000000..b5e64f19a0 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/UNLModify.h @@ -0,0 +1,177 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class UNLModifyBuilder; + +/** + * @brief Transaction: UNLModify + * + * Type: ttUNL_MODIFY (102) + * Delegable: Delegation::notDelegable + * Amendment: uint256{} + * Privileges: noPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use UNLModifyBuilder to construct new transactions. + */ +class UNLModify : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttUNL_MODIFY; + + /** + * @brief Construct a UNLModify transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit UNLModify(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for UNLModify"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfUNLModifyDisabling (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT8::type::value_type + getUNLModifyDisabling() const + { + return this->tx_->at(sfUNLModifyDisabling); + } + + /** + * @brief Get sfLedgerSequence (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT32::type::value_type + getLedgerSequence() const + { + return this->tx_->at(sfLedgerSequence); + } + + /** + * @brief Get sfUNLModifyValidator (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_VL::type::value_type + getUNLModifyValidator() const + { + return this->tx_->at(sfUNLModifyValidator); + } +}; + +/** + * @brief Builder for UNLModify transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class UNLModifyBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new UNLModifyBuilder with required fields. + * @param account The account initiating the transaction. + * @param uNLModifyDisabling The sfUNLModifyDisabling field value. + * @param ledgerSequence The sfLedgerSequence field value. + * @param uNLModifyValidator The sfUNLModifyValidator field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + UNLModifyBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& uNLModifyDisabling, std::decay_t const& ledgerSequence, std::decay_t const& uNLModifyValidator, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttUNL_MODIFY, account, sequence, fee) + { + setUNLModifyDisabling(uNLModifyDisabling); + setLedgerSequence(ledgerSequence); + setUNLModifyValidator(uNLModifyValidator); + } + + /** + * @brief Construct a UNLModifyBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + UNLModifyBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttUNL_MODIFY) + { + throw std::runtime_error("Invalid transaction type for UNLModifyBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfUNLModifyDisabling (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + UNLModifyBuilder& + setUNLModifyDisabling(std::decay_t const& value) + { + object_[sfUNLModifyDisabling] = value; + return *this; + } + + /** + * @brief Set sfLedgerSequence (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + UNLModifyBuilder& + setLedgerSequence(std::decay_t const& value) + { + object_[sfLedgerSequence] = value; + return *this; + } + + /** + * @brief Set sfUNLModifyValidator (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + UNLModifyBuilder& + setUNLModifyValidator(std::decay_t const& value) + { + object_[sfUNLModifyValidator] = value; + return *this; + } + + /** + * @brief Build and return the UNLModify wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + UNLModify + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return UNLModify{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/VaultClawback.h b/include/xrpl/protocol_autogen/transactions/VaultClawback.h new file mode 100644 index 0000000000..82b2b32e8d --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/VaultClawback.h @@ -0,0 +1,192 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class VaultClawbackBuilder; + +/** + * @brief Transaction: VaultClawback + * + * Type: ttVAULT_CLAWBACK (70) + * Delegable: Delegation::notDelegable + * Amendment: featureSingleAssetVault + * Privileges: mayDeleteMPT | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use VaultClawbackBuilder to construct new transactions. + */ +class VaultClawback : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttVAULT_CLAWBACK; + + /** + * @brief Construct a VaultClawback transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit VaultClawback(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for VaultClawback"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->tx_->at(sfVaultID); + } + + /** + * @brief Get sfHolder (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_ACCOUNT::type::value_type + getHolder() const + { + return this->tx_->at(sfHolder); + } + + /** + * @brief Get sfAmount (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAmount() const + { + if (hasAmount()) + { + return this->tx_->at(sfAmount); + } + return std::nullopt; + } + + /** + * @brief Check if sfAmount is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAmount() const + { + return this->tx_->isFieldPresent(sfAmount); + } +}; + +/** + * @brief Builder for VaultClawback transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class VaultClawbackBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new VaultClawbackBuilder with required fields. + * @param account The account initiating the transaction. + * @param vaultID The sfVaultID field value. + * @param holder The sfHolder field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + VaultClawbackBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& vaultID, std::decay_t const& holder, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttVAULT_CLAWBACK, account, sequence, fee) + { + setVaultID(vaultID); + setHolder(holder); + } + + /** + * @brief Construct a VaultClawbackBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + VaultClawbackBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttVAULT_CLAWBACK) + { + throw std::runtime_error("Invalid transaction type for VaultClawbackBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultClawbackBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfHolder (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultClawbackBuilder& + setHolder(std::decay_t const& value) + { + object_[sfHolder] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeOPTIONAL) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + VaultClawbackBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Build and return the VaultClawback wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + VaultClawback + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return VaultClawback{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/VaultCreate.h b/include/xrpl/protocol_autogen/transactions/VaultCreate.h new file mode 100644 index 0000000000..03d4d4b88d --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/VaultCreate.h @@ -0,0 +1,353 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class VaultCreateBuilder; + +/** + * @brief Transaction: VaultCreate + * + * Type: ttVAULT_CREATE (65) + * Delegable: Delegation::notDelegable + * Amendment: featureSingleAssetVault + * Privileges: createPseudoAcct | createMPTIssuance | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use VaultCreateBuilder to construct new transactions. + */ +class VaultCreate : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttVAULT_CREATE; + + /** + * @brief Construct a VaultCreate transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit VaultCreate(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for VaultCreate"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfAsset (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_ISSUE::type::value_type + getAsset() const + { + return this->tx_->at(sfAsset); + } + + /** + * @brief Get sfAssetsMaximum (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetsMaximum() const + { + if (hasAssetsMaximum()) + { + return this->tx_->at(sfAssetsMaximum); + } + return std::nullopt; + } + + /** + * @brief Check if sfAssetsMaximum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetsMaximum() const + { + return this->tx_->isFieldPresent(sfAssetsMaximum); + } + + /** + * @brief Get sfMPTokenMetadata (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getMPTokenMetadata() const + { + if (hasMPTokenMetadata()) + { + return this->tx_->at(sfMPTokenMetadata); + } + return std::nullopt; + } + + /** + * @brief Check if sfMPTokenMetadata is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasMPTokenMetadata() const + { + return this->tx_->isFieldPresent(sfMPTokenMetadata); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } + + /** + * @brief Get sfWithdrawalPolicy (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getWithdrawalPolicy() const + { + if (hasWithdrawalPolicy()) + { + return this->tx_->at(sfWithdrawalPolicy); + } + return std::nullopt; + } + + /** + * @brief Check if sfWithdrawalPolicy is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasWithdrawalPolicy() const + { + return this->tx_->isFieldPresent(sfWithdrawalPolicy); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + { + return this->tx_->at(sfData); + } + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->tx_->isFieldPresent(sfData); + } + + /** + * @brief Get sfScale (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getScale() const + { + if (hasScale()) + { + return this->tx_->at(sfScale); + } + return std::nullopt; + } + + /** + * @brief Check if sfScale is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasScale() const + { + return this->tx_->isFieldPresent(sfScale); + } +}; + +/** + * @brief Builder for VaultCreate transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class VaultCreateBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new VaultCreateBuilder with required fields. + * @param account The account initiating the transaction. + * @param asset The sfAsset field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + VaultCreateBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& asset, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttVAULT_CREATE, account, sequence, fee) + { + setAsset(asset); + } + + /** + * @brief Construct a VaultCreateBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + VaultCreateBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttVAULT_CREATE) + { + throw std::runtime_error("Invalid transaction type for VaultCreateBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfAsset (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setAsset(std::decay_t const& value) + { + object_[sfAsset] = STIssue(sfAsset, value); + return *this; + } + + /** + * @brief Set sfAssetsMaximum (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setAssetsMaximum(std::decay_t const& value) + { + object_[sfAssetsMaximum] = value; + return *this; + } + + /** + * @brief Set sfMPTokenMetadata (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setMPTokenMetadata(std::decay_t const& value) + { + object_[sfMPTokenMetadata] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfWithdrawalPolicy (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setWithdrawalPolicy(std::decay_t const& value) + { + object_[sfWithdrawalPolicy] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Set sfScale (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultCreateBuilder& + setScale(std::decay_t const& value) + { + object_[sfScale] = value; + return *this; + } + + /** + * @brief Build and return the VaultCreate wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + VaultCreate + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return VaultCreate{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/VaultDelete.h b/include/xrpl/protocol_autogen/transactions/VaultDelete.h new file mode 100644 index 0000000000..89a4ef2a2f --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/VaultDelete.h @@ -0,0 +1,129 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class VaultDeleteBuilder; + +/** + * @brief Transaction: VaultDelete + * + * Type: ttVAULT_DELETE (67) + * Delegable: Delegation::notDelegable + * Amendment: featureSingleAssetVault + * Privileges: mustDeleteAcct | destroyMPTIssuance | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use VaultDeleteBuilder to construct new transactions. + */ +class VaultDelete : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttVAULT_DELETE; + + /** + * @brief Construct a VaultDelete transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit VaultDelete(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for VaultDelete"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->tx_->at(sfVaultID); + } +}; + +/** + * @brief Builder for VaultDelete transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class VaultDeleteBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new VaultDeleteBuilder with required fields. + * @param account The account initiating the transaction. + * @param vaultID The sfVaultID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + VaultDeleteBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& vaultID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttVAULT_DELETE, account, sequence, fee) + { + setVaultID(vaultID); + } + + /** + * @brief Construct a VaultDeleteBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + VaultDeleteBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttVAULT_DELETE) + { + throw std::runtime_error("Invalid transaction type for VaultDeleteBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultDeleteBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Build and return the VaultDelete wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + VaultDelete + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return VaultDelete{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/VaultDeposit.h b/include/xrpl/protocol_autogen/transactions/VaultDeposit.h new file mode 100644 index 0000000000..4127638e57 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/VaultDeposit.h @@ -0,0 +1,155 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class VaultDepositBuilder; + +/** + * @brief Transaction: VaultDeposit + * + * Type: ttVAULT_DEPOSIT (68) + * Delegable: Delegation::notDelegable + * Amendment: featureSingleAssetVault + * Privileges: mayAuthorizeMPT | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use VaultDepositBuilder to construct new transactions. + */ +class VaultDeposit : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttVAULT_DEPOSIT; + + /** + * @brief Construct a VaultDeposit transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit VaultDeposit(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for VaultDeposit"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->tx_->at(sfVaultID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } +}; + +/** + * @brief Builder for VaultDeposit transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class VaultDepositBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new VaultDepositBuilder with required fields. + * @param account The account initiating the transaction. + * @param vaultID The sfVaultID field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + VaultDepositBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& vaultID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttVAULT_DEPOSIT, account, sequence, fee) + { + setVaultID(vaultID); + setAmount(amount); + } + + /** + * @brief Construct a VaultDepositBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + VaultDepositBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttVAULT_DEPOSIT) + { + throw std::runtime_error("Invalid transaction type for VaultDepositBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultDepositBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + VaultDepositBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Build and return the VaultDeposit wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + VaultDeposit + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return VaultDeposit{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/VaultSet.h b/include/xrpl/protocol_autogen/transactions/VaultSet.h new file mode 100644 index 0000000000..372697b5f7 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/VaultSet.h @@ -0,0 +1,240 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class VaultSetBuilder; + +/** + * @brief Transaction: VaultSet + * + * Type: ttVAULT_SET (66) + * Delegable: Delegation::notDelegable + * Amendment: featureSingleAssetVault + * Privileges: mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use VaultSetBuilder to construct new transactions. + */ +class VaultSet : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttVAULT_SET; + + /** + * @brief Construct a VaultSet transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit VaultSet(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for VaultSet"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->tx_->at(sfVaultID); + } + + /** + * @brief Get sfAssetsMaximum (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetsMaximum() const + { + if (hasAssetsMaximum()) + { + return this->tx_->at(sfAssetsMaximum); + } + return std::nullopt; + } + + /** + * @brief Check if sfAssetsMaximum is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetsMaximum() const + { + return this->tx_->isFieldPresent(sfAssetsMaximum); + } + + /** + * @brief Get sfDomainID (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getDomainID() const + { + if (hasDomainID()) + { + return this->tx_->at(sfDomainID); + } + return std::nullopt; + } + + /** + * @brief Check if sfDomainID is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasDomainID() const + { + return this->tx_->isFieldPresent(sfDomainID); + } + + /** + * @brief Get sfData (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getData() const + { + if (hasData()) + { + return this->tx_->at(sfData); + } + return std::nullopt; + } + + /** + * @brief Check if sfData is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasData() const + { + return this->tx_->isFieldPresent(sfData); + } +}; + +/** + * @brief Builder for VaultSet transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class VaultSetBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new VaultSetBuilder with required fields. + * @param account The account initiating the transaction. + * @param vaultID The sfVaultID field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + VaultSetBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& vaultID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttVAULT_SET, account, sequence, fee) + { + setVaultID(vaultID); + } + + /** + * @brief Construct a VaultSetBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + VaultSetBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttVAULT_SET) + { + throw std::runtime_error("Invalid transaction type for VaultSetBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultSetBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfAssetsMaximum (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultSetBuilder& + setAssetsMaximum(std::decay_t const& value) + { + object_[sfAssetsMaximum] = value; + return *this; + } + + /** + * @brief Set sfDomainID (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultSetBuilder& + setDomainID(std::decay_t const& value) + { + object_[sfDomainID] = value; + return *this; + } + + /** + * @brief Set sfData (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultSetBuilder& + setData(std::decay_t const& value) + { + object_[sfData] = value; + return *this; + } + + /** + * @brief Build and return the VaultSet wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + VaultSet + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return VaultSet{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/VaultWithdraw.h b/include/xrpl/protocol_autogen/transactions/VaultWithdraw.h new file mode 100644 index 0000000000..8b2a6a9a3c --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/VaultWithdraw.h @@ -0,0 +1,229 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class VaultWithdrawBuilder; + +/** + * @brief Transaction: VaultWithdraw + * + * Type: ttVAULT_WITHDRAW (69) + * Delegable: Delegation::notDelegable + * Amendment: featureSingleAssetVault + * Privileges: mayDeleteMPT | mayAuthorizeMPT | mustModifyVault + * + * Immutable wrapper around STTx providing type-safe field access. + * Use VaultWithdrawBuilder to construct new transactions. + */ +class VaultWithdraw : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttVAULT_WITHDRAW; + + /** + * @brief Construct a VaultWithdraw transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit VaultWithdraw(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for VaultWithdraw"); + } + } + + // Transaction-specific field getters + + /** + * @brief Get sfVaultID (soeREQUIRED) + * @return The field value. + */ + [[nodiscard]] + SF_UINT256::type::value_type + getVaultID() const + { + return this->tx_->at(sfVaultID); + } + + /** + * @brief Get sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return The field value. + */ + [[nodiscard]] + SF_AMOUNT::type::value_type + getAmount() const + { + return this->tx_->at(sfAmount); + } + + /** + * @brief Get sfDestination (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Get sfDestinationTag (soeOPTIONAL) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + 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 Builder for VaultWithdraw transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class VaultWithdrawBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new VaultWithdrawBuilder with required fields. + * @param account The account initiating the transaction. + * @param vaultID The sfVaultID field value. + * @param amount The sfAmount field value. + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + VaultWithdrawBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& vaultID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttVAULT_WITHDRAW, account, sequence, fee) + { + setVaultID(vaultID); + setAmount(amount); + } + + /** + * @brief Construct a VaultWithdrawBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + VaultWithdrawBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttVAULT_WITHDRAW) + { + throw std::runtime_error("Invalid transaction type for VaultWithdrawBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfVaultID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + VaultWithdrawBuilder& + setVaultID(std::decay_t const& value) + { + object_[sfVaultID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @note This field supports MPT (Multi-Purpose Token) amounts. + * @return Reference to this builder for method chaining. + */ + VaultWithdrawBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultWithdrawBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + VaultWithdrawBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Build and return the VaultWithdraw wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + VaultWithdraw + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return VaultWithdraw{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h b/include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h new file mode 100644 index 0000000000..aebfbea5d3 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainAccountCreateCommit.h @@ -0,0 +1,201 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainAccountCreateCommitBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& destination, std::decay_t const& amount, std::decay_t const& signatureReward, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAccountCreateCommitBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAccountCreateCommitBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfSignatureReward (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAccountCreateCommitBuilder& + setSignatureReward(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h b/include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h new file mode 100644 index 0000000000..08dc646470 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestation.h @@ -0,0 +1,369 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainAddAccountCreateAttestationBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& attestationSignerAccount, std::decay_t const& publicKey, std::decay_t const& signature, std::decay_t const& otherChainSource, std::decay_t const& amount, std::decay_t const& attestationRewardAccount, std::decay_t const& wasLockingChainSend, std::decay_t const& xChainAccountCreateCount, std::decay_t const& destination, std::decay_t const& signatureReward, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfAttestationSignerAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setAttestationSignerAccount(std::decay_t const& value) + { + object_[sfAttestationSignerAccount] = value; + return *this; + } + + /** + * @brief Set sfPublicKey (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setPublicKey(std::decay_t const& value) + { + object_[sfPublicKey] = value; + return *this; + } + + /** + * @brief Set sfSignature (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setSignature(std::decay_t const& value) + { + object_[sfSignature] = value; + return *this; + } + + /** + * @brief Set sfOtherChainSource (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setOtherChainSource(std::decay_t const& value) + { + object_[sfOtherChainSource] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfAttestationRewardAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setAttestationRewardAccount(std::decay_t const& value) + { + object_[sfAttestationRewardAccount] = value; + return *this; + } + + /** + * @brief Set sfWasLockingChainSend (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setWasLockingChainSend(std::decay_t const& value) + { + object_[sfWasLockingChainSend] = value; + return *this; + } + + /** + * @brief Set sfXChainAccountCreateCount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setXChainAccountCreateCount(std::decay_t const& value) + { + object_[sfXChainAccountCreateCount] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfSignatureReward (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddAccountCreateAttestationBuilder& + setSignatureReward(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h b/include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h new file mode 100644 index 0000000000..100fc855aa --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainAddClaimAttestation.h @@ -0,0 +1,358 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 + 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainAddClaimAttestationBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& attestationSignerAccount, std::decay_t const& publicKey, std::decay_t const& signature, std::decay_t const& otherChainSource, std::decay_t const& amount, std::decay_t const& attestationRewardAccount, std::decay_t const& wasLockingChainSend, std::decay_t const& xChainClaimID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfAttestationSignerAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setAttestationSignerAccount(std::decay_t const& value) + { + object_[sfAttestationSignerAccount] = value; + return *this; + } + + /** + * @brief Set sfPublicKey (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setPublicKey(std::decay_t const& value) + { + object_[sfPublicKey] = value; + return *this; + } + + /** + * @brief Set sfSignature (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setSignature(std::decay_t const& value) + { + object_[sfSignature] = value; + return *this; + } + + /** + * @brief Set sfOtherChainSource (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setOtherChainSource(std::decay_t const& value) + { + object_[sfOtherChainSource] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfAttestationRewardAccount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setAttestationRewardAccount(std::decay_t const& value) + { + object_[sfAttestationRewardAccount] = value; + return *this; + } + + /** + * @brief Set sfWasLockingChainSend (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setWasLockingChainSend(std::decay_t const& value) + { + object_[sfWasLockingChainSend] = value; + return *this; + } + + /** + * @brief Set sfXChainClaimID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setXChainClaimID(std::decay_t const& value) + { + object_[sfXChainClaimID] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + XChainAddClaimAttestationBuilder& + setDestination(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainClaim.h b/include/xrpl/protocol_autogen/transactions/XChainClaim.h new file mode 100644 index 0000000000..6b1b748677 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainClaim.h @@ -0,0 +1,238 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 + 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainClaimBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& xChainClaimID, std::decay_t const& destination, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfXChainClaimID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainClaimBuilder& + setXChainClaimID(std::decay_t const& value) + { + object_[sfXChainClaimID] = value; + return *this; + } + + /** + * @brief Set sfDestination (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainClaimBuilder& + setDestination(std::decay_t const& value) + { + object_[sfDestination] = value; + return *this; + } + + /** + * @brief Set sfDestinationTag (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + XChainClaimBuilder& + setDestinationTag(std::decay_t const& value) + { + object_[sfDestinationTag] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainClaimBuilder& + setAmount(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainCommit.h b/include/xrpl/protocol_autogen/transactions/XChainCommit.h new file mode 100644 index 0000000000..879c76f180 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainCommit.h @@ -0,0 +1,214 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 + 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainCommitBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& xChainClaimID, std::decay_t const& amount, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfXChainClaimID (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainCommitBuilder& + setXChainClaimID(std::decay_t const& value) + { + object_[sfXChainClaimID] = value; + return *this; + } + + /** + * @brief Set sfAmount (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainCommitBuilder& + setAmount(std::decay_t const& value) + { + object_[sfAmount] = value; + return *this; + } + + /** + * @brief Set sfOtherChainDestination (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + XChainCommitBuilder& + setOtherChainDestination(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h b/include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h new file mode 100644 index 0000000000..6ec22dd9fc --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainCreateBridge.h @@ -0,0 +1,190 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 + 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainCreateBridgeBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& signatureReward, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfSignatureReward (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainCreateBridgeBuilder& + setSignatureReward(std::decay_t const& value) + { + object_[sfSignatureReward] = value; + return *this; + } + + /** + * @brief Set sfMinAccountCreateAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + XChainCreateBridgeBuilder& + setMinAccountCreateAmount(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h b/include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h new file mode 100644 index 0000000000..ab76ee0e77 --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainCreateClaimID.h @@ -0,0 +1,177 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainCreateClaimIDBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::decay_t const& signatureReward, std::decay_t const& otherChainSource, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfSignatureReward (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainCreateClaimIDBuilder& + setSignatureReward(std::decay_t const& value) + { + object_[sfSignatureReward] = value; + return *this; + } + + /** + * @brief Set sfOtherChainSource (soeREQUIRED) + * @return Reference to this builder for method chaining. + */ + XChainCreateClaimIDBuilder& + setOtherChainSource(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h b/include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h new file mode 100644 index 0000000000..b57e0fdbdc --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/XChainModifyBridge.h @@ -0,0 +1,203 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 + 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 + 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 Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class XChainModifyBridgeBuilder : public TransactionBuilderBase +{ +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 const& xChainBridge, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(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 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 const& value) + { + object_[sfXChainBridge] = value; + return *this; + } + + /** + * @brief Set sfSignatureReward (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + XChainModifyBridgeBuilder& + setSignatureReward(std::decay_t const& value) + { + object_[sfSignatureReward] = value; + return *this; + } + + /** + * @brief Set sfMinAccountCreateAmount (soeOPTIONAL) + * @return Reference to this builder for method chaining. + */ + XChainModifyBridgeBuilder& + setMinAccountCreateAmount(std::decay_t 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(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/scripts/generate_ledger_classes.py b/scripts/generate_ledger_classes.py new file mode 100644 index 0000000000..ad773ab9af --- /dev/null +++ b/scripts/generate_ledger_classes.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +""" +Generate C++ wrapper classes for XRP Ledger entry types from ledger_entries.macro. + +This script parses the ledger_entries.macro file and generates type-safe wrapper +classes for each ledger entry type, similar to the transaction wrapper classes. + +Uses pcpp to preprocess the macro file and pyparsing to parse the DSL. +""" + +import io +import argparse +from pathlib import Path +import pyparsing as pp + +# Import common utilities +from macro_parser_common import ( + CppCleaner, + parse_sfields_macro, + parse_field_list, + generate_cpp_class, + generate_from_template, + clear_output_directory, +) + + +def create_ledger_entry_parser(): + """Create a pyparsing parser for LEDGER_ENTRY macros. + + This parser extracts the full LEDGER_ENTRY macro call and parses its arguments + using pyparsing's nesting-aware delimited list parsing. + """ + # Match the exact words + ledger_entry = pp.Keyword("LEDGER_ENTRY") | pp.Keyword("LEDGER_ENTRY_DUPLICATE") + + # Define nested structures so pyparsing protects them + nested_braces = pp.original_text_for(pp.nested_expr("{", "}")) + nested_parens = pp.original_text_for(pp.nested_expr("(", ")")) + + # Define standard text (anything that isn't a comma, parens, or braces) + plain_text = pp.Word(pp.printables + " \t\n", exclude_chars=",{}()") + + # A single argument is any combination of the above + single_arg = pp.Combine(pp.OneOrMore(nested_braces | nested_parens | plain_text)) + single_arg.set_parse_action(lambda t: t[0].strip()) + + # The arguments are a delimited list + args_list = pp.DelimitedList(single_arg) + + # The full macro: LEDGER_ENTRY(args) or LEDGER_ENTRY_DUPLICATE(args) + macro_parser = ( + ledger_entry + pp.Suppress("(") + pp.Group(args_list)("args") + pp.Suppress(")") + ) + + return macro_parser + + +def parse_ledger_entry_args(args_list): + """Parse the arguments of a LEDGER_ENTRY macro call. + + Args: + args_list: A list of parsed arguments from pyparsing, e.g., + ['ltACCOUNT_ROOT', '0x0061', 'AccountRoot', 'account', '({...})'] + + Returns: + A dict with parsed ledger entry information. + """ + if len(args_list) < 5: + raise ValueError( + f"Expected at least 5 parts in LEDGER_ENTRY, got {len(args_list)}: {args_list}" + ) + + tag = args_list[0] + value = args_list[1] + name = args_list[2] + rpc_name = args_list[3] + fields_str = args_list[-1] + + # Parse fields: ({field1, field2, ...}) + fields = parse_field_list(fields_str) + + return { + "tag": tag, + "value": value, + "name": name, + "rpc_name": rpc_name, + "fields": fields, + } + + +def parse_macro_file(file_path): + """Parse the ledger_entries.macro file and return a list of ledger entry definitions. + + Uses pcpp to preprocess the file and pyparsing to parse the LEDGER_ENTRY macros. + """ + with open(file_path, "r") as f: + c_code = f.read() + + # Step 1: Clean the C++ code using pcpp + cleaner = CppCleaner("LEDGER_ENTRY_INCLUDE", "LEDGER_ENTRY") + cleaner.parse(c_code) + + out = io.StringIO() + cleaner.write(out) + clean_text = out.getvalue() + + # Step 2: Parse the clean text using pyparsing + parser = create_ledger_entry_parser() + entries = [] + + for match, _, _ in parser.scan_string(clean_text): + # Extract the macro name and arguments + raw_args = match.args + + # Parse the arguments + entry_data = parse_ledger_entry_args(raw_args) + entries.append(entry_data) + + return entries + + +def main(): + parser = argparse.ArgumentParser( + description="Generate C++ ledger entry classes from ledger_entries.macro" + ) + parser.add_argument("macro_path", help="Path to ledger_entries.macro") + parser.add_argument( + "--header-dir", + help="Output directory for header files", + default="include/xrpl/protocol_autogen/ledger_entries", + ) + parser.add_argument( + "--test-dir", + help="Output directory for test files (optional)", + default=None, + ) + parser.add_argument( + "--sfields-macro", + help="Path to sfields.macro (default: auto-detect from macro_path)", + ) + parser.add_argument( + "--list-outputs", + action="store_true", + help="List output files without generating (one per line)", + ) + + args = parser.parse_args() + + # Parse the macro file to get ledger entry names + entries = parse_macro_file(args.macro_path) + + # If --list-outputs, just print the output file paths and exit + if args.list_outputs: + header_dir = Path(args.header_dir) + for entry in entries: + print(header_dir / f"{entry['name']}.h") + if args.test_dir: + test_dir = Path(args.test_dir) + for entry in entries: + print(test_dir / f"{entry['name']}Tests.cpp") + return + + # Auto-detect sfields.macro path if not provided + if args.sfields_macro: + sfields_path = Path(args.sfields_macro) + else: + # Assume sfields.macro is in the same directory as ledger_entries.macro + macro_path = Path(args.macro_path) + sfields_path = macro_path.parent / "sfields.macro" + + # Parse sfields.macro to get field type information + print(f"Parsing {sfields_path}...") + field_types = parse_sfields_macro(sfields_path) + print( + f"Found {len(field_types)} field definitions ({sum(1 for f in field_types.values() if f['typed'])} typed, {sum(1 for f in field_types.values() if not f['typed'])} untyped)\n" + ) + + print(f"Found {len(entries)} ledger entries\n") + + for entry in entries: + print(f"Ledger Entry: {entry['name']}") + print(f" Tag: {entry['tag']}") + print(f" Value: {entry['value']}") + print(f" RPC Name: {entry['rpc_name']}") + print(f" Fields: {len(entry['fields'])}") + for field in entry["fields"]: + mpt_info = f" ({field['mpt_support']})" if "mpt_support" in field else "" + print(f" - {field['name']}: {field['requirement']}{mpt_info}") + print() + + # Set up template directory + script_dir = Path(__file__).parent + template_dir = script_dir / "templates" + + # Generate C++ classes + header_dir = Path(args.header_dir) + header_dir.mkdir(parents=True, exist_ok=True) + + # Clear existing generated files before regenerating + clear_output_directory(header_dir) + + for entry in entries: + generate_cpp_class( + entry, header_dir, template_dir, field_types, "LedgerEntry.h.mako" + ) + + print(f"\nGenerated {len(entries)} ledger entry classes") + + # Generate unit tests if --test-dir is provided + if args.test_dir: + test_dir = Path(args.test_dir) + test_dir.mkdir(parents=True, exist_ok=True) + + # Clear existing generated test files before regenerating + clear_output_directory(test_dir) + + for entry in entries: + # Fields are already enriched from generate_cpp_class above + generate_from_template( + entry, test_dir, template_dir, "LedgerEntryTests.cpp.mako", "Tests.cpp" + ) + + print(f"\nGenerated {len(entries)} ledger entry test files") + + +if __name__ == "__main__": + main() diff --git a/scripts/generate_tx_classes.py b/scripts/generate_tx_classes.py new file mode 100644 index 0000000000..f21b7101df --- /dev/null +++ b/scripts/generate_tx_classes.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +""" +Parse transactions.macro file to extract transaction information +and generate C++ classes for each transaction type. + +Uses pcpp to preprocess the macro file and pyparsing to parse the DSL. +""" + +import io +import argparse +from pathlib import Path +import pyparsing as pp + +# Import common utilities +from macro_parser_common import ( + CppCleaner, + parse_sfields_macro, + parse_field_list, + generate_cpp_class, + generate_from_template, + clear_output_directory, +) + + +def create_transaction_parser(): + """Create a pyparsing parser for TRANSACTION macros. + + This parser extracts the full TRANSACTION macro call and parses its arguments + using pyparsing's nesting-aware delimited list parsing. + """ + # Define nested structures so pyparsing protects them + nested_braces = pp.original_text_for(pp.nested_expr("{", "}")) + nested_parens = pp.original_text_for(pp.nested_expr("(", ")")) + + # Define standard text (anything that isn't a comma, parens, or braces) + plain_text = pp.Word(pp.printables + " \t\n", exclude_chars=",{}()") + + # A single argument is any combination of the above + single_arg = pp.Combine(pp.OneOrMore(nested_braces | nested_parens | plain_text)) + single_arg.set_parse_action(lambda t: t[0].strip()) + + # The arguments are a delimited list + args_list = pp.DelimitedList(single_arg) + + # The full macro: TRANSACTION(args) + macro_parser = ( + pp.Keyword("TRANSACTION") + + pp.Suppress("(") + + pp.Group(args_list)("args") + + pp.Suppress(")") + ) + + return macro_parser + + +def parse_transaction_args(args_list): + """Parse the arguments of a TRANSACTION macro call. + + Args: + args_list: A list of parsed arguments from pyparsing, e.g., + ['ttPAYMENT', '0', 'Payment', 'Delegation::delegable', + 'uint256{}', 'createAcct', '({...})'] + + Returns: + A dict with parsed transaction information. + """ + if len(args_list) < 7: + raise ValueError( + f"Expected at least 7 parts in TRANSACTION, got {len(args_list)}: {args_list}" + ) + + tag = args_list[0] + value = args_list[1] + name = args_list[2] + delegable = args_list[3] + amendments = args_list[4] + privileges = args_list[5] + fields_str = args_list[-1] + + # Parse fields: ({field1, field2, ...}) + fields = parse_field_list(fields_str) + + return { + "tag": tag, + "value": value, + "name": name, + "delegable": delegable, + "amendments": amendments, + "privileges": privileges, + "fields": fields, + } + + +def parse_macro_file(filepath): + """Parse the transactions.macro file. + + Uses pcpp to preprocess the file and pyparsing to parse the TRANSACTION macros. + """ + with open(filepath, "r") as f: + c_code = f.read() + + # Step 1: Clean the C++ code using pcpp + cleaner = CppCleaner("TRANSACTION_INCLUDE", "TRANSACTION") + cleaner.parse(c_code) + + out = io.StringIO() + cleaner.write(out) + clean_text = out.getvalue() + + # Step 2: Parse the clean text using pyparsing + parser = create_transaction_parser() + transactions = [] + + for match, _, _ in parser.scan_string(clean_text): + # Extract the macro name and arguments + raw_args = match.args + + # Parse the arguments + tx_data = parse_transaction_args(raw_args) + transactions.append(tx_data) + + return transactions + + +# TransactionBase is a static file in the repository at: +# - include/xrpl/protocol/TransactionBase.h +# - src/libxrpl/protocol/TransactionBase.cpp +# It is NOT generated by this script. + + +def main(): + parser = argparse.ArgumentParser( + description="Generate C++ transaction classes from transactions.macro" + ) + parser.add_argument("macro_path", help="Path to transactions.macro") + parser.add_argument( + "--header-dir", + help="Output directory for header files", + default="include/xrpl/protocol_autogen/transactions", + ) + parser.add_argument( + "--test-dir", + help="Output directory for test files (optional)", + default=None, + ) + parser.add_argument( + "--sfields-macro", + help="Path to sfields.macro (default: auto-detect from macro_path)", + ) + parser.add_argument( + "--list-outputs", + action="store_true", + help="List output files without generating (one per line)", + ) + + args = parser.parse_args() + + # Parse the macro file to get transaction names + transactions = parse_macro_file(args.macro_path) + + # If --list-outputs, just print the output file paths and exit + if args.list_outputs: + header_dir = Path(args.header_dir) + for tx in transactions: + print(header_dir / f"{tx['name']}.h") + if args.test_dir: + test_dir = Path(args.test_dir) + for tx in transactions: + print(test_dir / f"{tx['name']}Tests.cpp") + return + + # Auto-detect sfields.macro path if not provided + if args.sfields_macro: + sfields_path = Path(args.sfields_macro) + else: + # Assume sfields.macro is in the same directory as transactions.macro + macro_path = Path(args.macro_path) + sfields_path = macro_path.parent / "sfields.macro" + + # Parse sfields.macro to get field type information + print(f"Parsing {sfields_path}...") + field_types = parse_sfields_macro(sfields_path) + print( + f"Found {len(field_types)} field definitions ({sum(1 for f in field_types.values() if f['typed'])} typed, {sum(1 for f in field_types.values() if not f['typed'])} untyped)\n" + ) + + print(f"Found {len(transactions)} transactions\n") + + for tx in transactions: + print(f"Transaction: {tx['name']}") + print(f" Tag: {tx['tag']}") + print(f" Value: {tx['value']}") + print(f" Fields: {len(tx['fields'])}") + for field in tx["fields"]: + print(f" - {field['name']}: {field['requirement']}") + print() + + # Set up output directory + header_dir = Path(args.header_dir) + header_dir.mkdir(parents=True, exist_ok=True) + + # Clear existing generated files before regenerating + clear_output_directory(header_dir) + + print(f"\nGenerating header-only template classes...") + print(f" Headers: {header_dir}\n") + + # Set up template directory + script_dir = Path(__file__).parent + template_dir = script_dir / "templates" + + generated_files = [] + for tx_info in transactions: + header_path = generate_cpp_class( + tx_info, header_dir, template_dir, field_types, "Transaction.h.mako" + ) + generated_files.append(header_path) + print(f" Generated: {tx_info['name']}.h") + + print( + f"\nGenerated {len(transactions)} transaction classes ({len(generated_files)} header files)" + ) + print(f" Headers: {header_dir.absolute()}") + + # Generate unit tests if --test-dir is provided + if args.test_dir: + test_dir = Path(args.test_dir) + test_dir.mkdir(parents=True, exist_ok=True) + + # Clear existing generated test files before regenerating + clear_output_directory(test_dir) + + for tx_info in transactions: + # Fields are already enriched from generate_cpp_class above + generate_from_template( + tx_info, + test_dir, + template_dir, + "TransactionTests.cpp.mako", + "Tests.cpp", + ) + + print(f"\nGenerated {len(transactions)} transaction test files") + + +if __name__ == "__main__": + main() diff --git a/scripts/macro_parser_common.py b/scripts/macro_parser_common.py new file mode 100644 index 0000000000..eae4df39db --- /dev/null +++ b/scripts/macro_parser_common.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 +""" +Common utilities for parsing XRP Ledger macro files. + +This module provides shared functionality for parsing transactions.macro +and ledger_entries.macro files using pcpp and pyparsing. +""" + +import re +import shutil +from pathlib import Path +import pyparsing as pp +from pcpp import Preprocessor + + +def clear_output_directory(directory): + """Clear all generated files from an output directory. + + Removes all .h and .cpp files from the directory, but preserves + the directory itself and any subdirectories. + + Args: + directory: Path to the directory to clear + """ + dir_path = Path(directory) + if not dir_path.exists(): + return + + # Remove generated files (headers and source files) + for pattern in ["*.h", "*.cpp"]: + for file_path in dir_path.glob(pattern): + file_path.unlink() + + print(f"Cleared output directory: {dir_path}") + + +class CppCleaner(Preprocessor): + """C preprocessor that removes C++ noise while preserving macro calls.""" + + def __init__(self, macro_include_name, macro_name): + """ + Initialize the preprocessor. + + Args: + macro_include_name: The name of the include flag to set to 0 + (e.g., "TRANSACTION_INCLUDE" or "LEDGER_ENTRY_INCLUDE") + macro_name: The name of the macro to define so #if !defined() checks pass + (e.g., "TRANSACTION" or "LEDGER_ENTRY") + """ + super(CppCleaner, self).__init__() + # Define flags so #if blocks evaluate correctly + # We set the include flag to 0 so includes are skipped + self.define(f"{macro_include_name} 0") + # Define the macro so #if !defined(MACRO) / #error checks pass + # We define it to expand to itself so the macro calls remain in the output + # for pyparsing to find and parse + self.define(f"{macro_name}(...) {macro_name}(__VA_ARGS__)") + # Suppress line directives + self.line_directive = None + + def on_error(self, file, line, msg): + # Ignore #error directives + pass + + def on_include_not_found( + self, is_malformed, is_system_include, curdir, includepath + ): + # Ignore missing headers + pass + + +def parse_sfields_macro(sfields_path): + """ + Parse sfields.macro to determine which fields are typed vs untyped. + + Returns a dict mapping field names to their type information: + { + 'sfMemos': {'typed': False, 'stiSuffix': 'ARRAY', 'typeData': {...}}, + 'sfAmount': {'typed': True, 'stiSuffix': 'AMOUNT', 'typeData': {...}}, + ... + } + """ + # Mapping from STI suffix to C++ type for untyped fields + UNTYPED_TYPE_MAP = { + "ARRAY": { + "getter_method": "getFieldArray", + "setter_method": "setFieldArray", + "setter_use_brackets": False, + "setter_type": "STArray const&", + "return_type": "STArray const&", + "return_type_optional": "std::optional>", + }, + "OBJECT": { + "getter_method": "getFieldObject", + "setter_method": "setFieldObject", + "setter_use_brackets": False, + "setter_type": "STObject const&", + "return_type": "STObject", + "return_type_optional": "std::optional", + }, + "PATHSET": { + "getter_method": "getFieldPathSet", + "setter_method": "setFieldPathSet", + "setter_use_brackets": False, + "setter_type": "STPathSet const&", + "return_type": "STPathSet const&", + "return_type_optional": "std::optional>", + }, + } + + field_info = {} + + with open(sfields_path, "r") as f: + content = f.read() + + # Parse TYPED_SFIELD entries + # Format: TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) + typed_pattern = r"TYPED_SFIELD\s*\(\s*(\w+)\s*,\s*(\w+)\s*," + for match in re.finditer(typed_pattern, content): + field_name = match.group(1) + sti_suffix = match.group(2) + field_info[field_name] = { + "typed": True, + "stiSuffix": sti_suffix, + "typeData": { + "getter_method": "at", + "setter_method": "", + "setter_use_brackets": True, + "setter_type": f"std::decay_t const&", + "return_type": f"SF_{sti_suffix}::type::value_type", + "return_type_optional": f"protocol_autogen::Optional", + }, + } + + # Parse UNTYPED_SFIELD entries + # Format: UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) + untyped_pattern = r"UNTYPED_SFIELD\s*\(\s*(\w+)\s*,\s*(\w+)\s*," + for match in re.finditer(untyped_pattern, content): + field_name = match.group(1) + sti_suffix = match.group(2) + type_data = UNTYPED_TYPE_MAP.get( + sti_suffix, UNTYPED_TYPE_MAP.get("OBJECT") + ) # Default to OBJECT + field_info[field_name] = { + "typed": False, + "stiSuffix": sti_suffix, + "typeData": type_data, + } + + return field_info + + +def create_field_list_parser(): + """Create a pyparsing parser for field lists like '({...})'.""" + # A field identifier (e.g., sfDestination, soeREQUIRED, soeMPTSupported) + field_identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_") + + # A single field definition: {sfName, soeREQUIRED, ...} + # Allow optional trailing comma inside the braces + field_def = ( + pp.Suppress("{") + + pp.Group(pp.DelimitedList(field_identifier) + pp.Optional(pp.Suppress(",")))( + "parts" + ) + + pp.Suppress("}") + ) + + # The field list: ({field1, field2, ...}) or ({}) for empty lists + # Allow optional trailing comma after the last field definition + field_list = ( + pp.Suppress("(") + + pp.Suppress("{") + + pp.Group( + pp.Optional(pp.DelimitedList(field_def) + pp.Optional(pp.Suppress(","))) + )("fields") + + pp.Suppress("}") + + pp.Suppress(")") + ) + + return field_list + + +def parse_field_list(fields_str): + """Parse a field list string like '({...})' using pyparsing. + + Args: + fields_str: A string like '({ + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED, soeMPTSupported} + })' + + Returns: + A list of field dicts with 'name', 'requirement', 'flags', and 'supports_mpt'. + """ + parser = create_field_list_parser() + + try: + result = parser.parse_string(fields_str, parse_all=True) + fields = [] + + for field_parts in result.fields: + if len(field_parts) < 2: + continue + + field_name = field_parts[0] + requirement = field_parts[1] + flags = list(field_parts[2:]) if len(field_parts) > 2 else [] + supports_mpt = "soeMPTSupported" in flags + + fields.append( + { + "name": field_name, + "requirement": requirement, + "flags": flags, + "supports_mpt": supports_mpt, + } + ) + + return fields + except pp.ParseException as e: + raise ValueError(f"Failed to parse field list: {e}") + + +def enrich_fields_with_type_data(entry_info, field_types): + """Enrich field information with type data from sfields.macro. + + Args: + entry_info: Dict containing entry information (name, fields, etc.) + field_types: Dict mapping field names to type information + + Modifies entry_info["fields"] in place. + """ + for field in entry_info["fields"]: + field_name = field["name"] + if field_name in field_types: + field["typed"] = field_types[field_name]["typed"] + field["paramName"] = field_name[2].lower() + field_name[3:] + field["stiSuffix"] = field_types[field_name]["stiSuffix"] + field["typeData"] = field_types[field_name]["typeData"] + else: + # Unknown field - assume typed for safety + field["typed"] = True + field["paramName"] = "" + field["stiSuffix"] = None + field["typeData"] = None + + +def generate_from_template( + entry_info, output_dir, template_dir, template_name, output_suffix +): + """Generate a file from a Mako template. + + Args: + entry_info: Dict containing entry information (name, fields, etc.) + Fields should already be enriched with type data. + output_dir: Output directory for generated files + template_dir: Directory containing Mako templates + template_name: Name of the Mako template file to use + output_suffix: Suffix for the output file (e.g., ".h" or "Tests.cpp") + + Returns: + Path to the generated file + """ + from mako.template import Template + + template_path = Path(template_dir) / template_name + template = Template(filename=str(template_path)) + + # Render the template - pass entry_info directly so templates can access any field + content = template.render(**entry_info) + + # Write output file in binary mode to avoid any line ending conversion + output_path = Path(output_dir) / f"{entry_info['name']}{output_suffix}" + with open(output_path, "wb") as f: + f.write(content.encode("utf-8")) + + print(f"Generated {output_path}") + return output_path + + +def generate_cpp_class( + entry_info, header_dir, template_dir, field_types, template_name +): + """Generate C++ header file from a Mako template. + + Args: + entry_info: Dict containing entry information (name, fields, etc.) + header_dir: Output directory for generated header files + template_dir: Directory containing Mako templates + field_types: Dict mapping field names to type information + template_name: Name of the Mako template file to use + """ + # Enrich field information with type data + enrich_fields_with_type_data(entry_info, field_types) + + # Generate the header file + generate_from_template(entry_info, header_dir, template_dir, template_name, ".h") diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 0000000000..40b472078d --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1,13 @@ +# Python dependencies for XRP Ledger code generation scripts +# +# These packages are required to run the code generation scripts that +# parse macro files and generate C++ wrapper classes. + +# C preprocessor for Python - used to preprocess macro files +pcpp>=1.30 + +# Parser combinator library - used to parse the macro DSL +pyparsing>=3.0.0 + +# Template engine - used to generate C++ code from templates +Mako>=1.2.0 diff --git a/scripts/templates/LedgerEntry.h.mako b/scripts/templates/LedgerEntry.h.mako new file mode 100644 index 0000000000..fdb55a973a --- /dev/null +++ b/scripts/templates/LedgerEntry.h.mako @@ -0,0 +1,216 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::ledger_entries { + +class ${name}Builder; + +/** + * @brief Ledger Entry: ${name} + * + * Type: ${tag} (${value}) + * RPC Name: ${rpc_name} + * + * Immutable wrapper around SLE providing type-safe field access. + * Use ${name}Builder to construct new ledger entries. + */ +class ${name} : public LedgerEntryBase +{ +public: + static constexpr LedgerEntryType entryType = ${tag}; + + /** + * @brief Construct a ${name} ledger entry wrapper from an existing SLE object. + * @throws std::runtime_error if the ledger entry type doesn't match. + */ + explicit ${name}(std::shared_ptr sle) + : LedgerEntryBase(std::move(sle)) + { + // Verify ledger entry type + if (sle_->getType() != entryType) + { + throw std::runtime_error("Invalid ledger entry type for ${name}"); + } + } + + // Ledger entry-specific field getters +% for field in fields: +% if field['typed']: + + /** + * @brief Get ${field['name']} (${field['requirement']}) +% if field.get('mpt_support'): + * MPT Support: ${field['mpt_support']} +% endif +% if field['requirement'] == 'soeREQUIRED': + * @return The field value. +% else: + * @return The field value, or std::nullopt if not present. +% endif + */ +% if field['requirement'] == 'soeREQUIRED': + [[nodiscard]] + ${field['typeData']['return_type']} + get${field['name'][2:]}() const + { + return this->sle_->${field['typeData']['getter_method']}(${field['name']}); + } +% else: + [[nodiscard]] + ${field['typeData']['return_type_optional']} + get${field['name'][2:]}() const + { + if (has${field['name'][2:]}()) + return this->sle_->${field['typeData']['getter_method']}(${field['name']}); + return std::nullopt; + } + + /** + * @brief Check if ${field['name']} is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + has${field['name'][2:]}() const + { + return this->sle_->isFieldPresent(${field['name']}); + } +% endif +% else: + + /** + * @brief Get ${field['name']} (${field['requirement']}) +% if field.get('mpt_support'): + * MPT Support: ${field['mpt_support']} +% endif + * @note This is an untyped field (${field.get('cppType', 'unknown')}). +% if field['requirement'] == 'soeREQUIRED': + * @return The field value. +% else: + * @return The field value, or std::nullopt if not present. +% endif + */ +% if field['requirement'] == 'soeREQUIRED': + [[nodiscard]] + ${field['typeData']['return_type']} + get${field['name'][2:]}() const + { + return this->sle_->${field['typeData']['getter_method']}(${field['name']}); + } +% else: + [[nodiscard]] + ${field['typeData']['return_type_optional']} + get${field['name'][2:]}() const + { + if (this->sle_->isFieldPresent(${field['name']})) + return this->sle_->${field['typeData']['getter_method']}(${field['name']}); + return std::nullopt; + } + + /** + * @brief Check if ${field['name']} is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + has${field['name'][2:]}() const + { + return this->sle_->isFieldPresent(${field['name']}); + } +% endif +% endif +% endfor +}; + +<% + required_fields = [f for f in fields if f['requirement'] == 'soeREQUIRED'] +%>\ +/** + * @brief Builder for ${name} ledger entries. + * + * Provides a fluent interface for constructing ledger entries with method chaining. + * Uses Json::Value internally for flexible ledger entry construction. + * Inherits common field setters from LedgerEntryBuilderBase. + */ +class ${name}Builder : public LedgerEntryBuilderBase<${name}Builder> +{ +public: + /** + * @brief Construct a new ${name}Builder with required fields. +% for field in required_fields: + * @param ${field['paramName']} The ${field['name']} field value. +% endfor + */ + ${name}Builder(\ +% for i, field in enumerate(required_fields): +${field['typeData']['setter_type']} ${field['paramName']}${',' if i < len(required_fields) - 1 else ''}\ +% endfor +) + : LedgerEntryBuilderBase<${name}Builder>(${tag}) + { +% for field in required_fields: + set${field['name'][2:]}(${field['paramName']}); +% endfor + } + + /** + * @brief Construct a ${name}Builder 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. + */ + ${name}Builder(std::shared_ptr sle) + { + if (sle->at(sfLedgerEntryType) != ${tag}) + { + throw std::runtime_error("Invalid ledger entry type for ${name}"); + } + object_ = *sle; + } + + /** @brief Ledger entry-specific field setters */ +% for field in fields: + + /** + * @brief Set ${field['name']} (${field['requirement']}) +% if field.get('mpt_support'): + * MPT Support: ${field['mpt_support']} +% endif + * @return Reference to this builder for method chaining. + */ + ${name}Builder& + set${field['name'][2:]}(${field['typeData']['setter_type']} value) + { +% if field.get('stiSuffix') == 'ISSUE': + object_[${field['name']}] = STIssue(${field['name']}, value); +% elif field['typeData'].get('setter_use_brackets'): + object_[${field['name']}] = value; +% else: + object_.${field['typeData']['setter_method']}(${field['name']}, value); +% endif + return *this; + } +% endfor + + /** + * @brief Build and return the completed ${name} wrapper. + * @param index The ledger entry index. + * @return The constructed ledger entry wrapper. + */ + ${name} + build(uint256 const& index) + { + return ${name}{std::make_shared(std::move(object_), index)}; + } +}; + +} // namespace xrpl::ledger_entries diff --git a/scripts/templates/LedgerEntryTests.cpp.mako b/scripts/templates/LedgerEntryTests.cpp.mako new file mode 100644 index 0000000000..35ce57f17b --- /dev/null +++ b/scripts/templates/LedgerEntryTests.cpp.mako @@ -0,0 +1,231 @@ +// Auto-generated unit tests for ledger entry ${name} +<% + required_fields = [f for f in fields if f["requirement"] == "soeREQUIRED"] + optional_fields = [f for f in fields if f["requirement"] != "soeREQUIRED"] + + def canonical_expr(field): + return f"canonical_{field['stiSuffix']}()" + + # Pick a wrong ledger entry to test type mismatch + # Use Ticket as it has minimal required fields (just Account) + if name != "Ticket": + wrong_le_include = "Ticket" + else: + wrong_le_include = "Check" +%> + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(${name}Tests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + +% for field in fields: + auto const ${field["paramName"]}Value = ${canonical_expr(field)}; +% endfor + + ${name}Builder builder{ +% for i, field in enumerate(required_fields): + ${field["paramName"]}Value${"," if i < len(required_fields) - 1 else ""} +% endfor + }; + +% for field in optional_fields: + builder.set${field["name"][2:]}(${field["paramName"]}Value); +% endfor + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + +% for field in required_fields: + { + auto const& expected = ${field["paramName"]}Value; + auto const actual = entry.get${field["name"][2:]}(); + expectEqualField(expected, actual, "${field["name"]}"); + } + +% endfor +% for field in optional_fields: + { + auto const& expected = ${field["paramName"]}Value; + auto const actualOpt = entry.get${field["name"][2:]}(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "${field["name"]}"); + EXPECT_TRUE(entry.has${field["name"][2:]}()); + } + +% endfor + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(${name}Tests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + +% for field in fields: + auto const ${field["paramName"]}Value = ${canonical_expr(field)}; +% endfor + + auto sle = std::make_shared(${name}::entryType, index); + +% for field in fields: +% if field.get("stiSuffix") == "ISSUE": + sle->at(${field["name"]}) = STIssue(${field["name"]}, ${field["paramName"]}Value); +% elif field["typeData"].get("setter_use_brackets"): + sle->at(${field["name"]}) = ${field["paramName"]}Value; +% else: + sle->${field["typeData"]["setter_method"]}(${field["name"]}, ${field["paramName"]}Value); +% endif +% endfor + + ${name}Builder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + ${name} entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + +% for field in required_fields: + { + auto const& expected = ${field["paramName"]}Value; + + auto const fromSle = entryFromSle.get${field["name"][2:]}(); + auto const fromBuilder = entryFromBuilder.get${field["name"][2:]}(); + + expectEqualField(expected, fromSle, "${field["name"]}"); + expectEqualField(expected, fromBuilder, "${field["name"]}"); + } + +% endfor +% for field in optional_fields: + { + auto const& expected = ${field["paramName"]}Value; + + auto const fromSleOpt = entryFromSle.get${field["name"][2:]}(); + auto const fromBuilderOpt = entryFromBuilder.get${field["name"][2:]}(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "${field["name"]}"); + expectEqualField(expected, *fromBuilderOpt, "${field["name"]}"); + } + +% endfor + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(${name}Tests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq +% if wrong_le_include == "Ticket": + ${wrong_le_include}Builder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; +% else: + ${wrong_le_include}Builder wrongBuilder{ + canonical_ACCOUNT(), + canonical_ACCOUNT(), + canonical_AMOUNT(), + canonical_UINT32(), + canonical_UINT64(), + canonical_UINT64(), + canonical_UINT256(), + canonical_UINT32()}; +% endif + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(${name}{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(${name}Tests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type +% if wrong_le_include == "Ticket": + ${wrong_le_include}Builder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; +% else: + ${wrong_le_include}Builder wrongBuilder{ + canonical_ACCOUNT(), + canonical_ACCOUNT(), + canonical_AMOUNT(), + canonical_UINT32(), + canonical_UINT64(), + canonical_UINT64(), + canonical_UINT256(), + canonical_UINT32()}; +% endif + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(${name}Builder{wrongEntry.getSle()}, std::runtime_error); +} + +% if optional_fields: +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(${name}Tests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + +% for field in required_fields: + auto const ${field["paramName"]}Value = ${canonical_expr(field)}; +% endfor + + ${name}Builder builder{ +% for i, field in enumerate(required_fields): + ${field["paramName"]}Value${"," if i < len(required_fields) - 1 else ""} +% endfor + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present +% for field in optional_fields: + EXPECT_FALSE(entry.has${field["name"][2:]}()); + EXPECT_FALSE(entry.get${field["name"][2:]}().has_value()); +% endfor +} +% endif +} diff --git a/scripts/templates/Transaction.h.mako b/scripts/templates/Transaction.h.mako new file mode 100644 index 0000000000..62c51a5c97 --- /dev/null +++ b/scripts/templates/Transaction.h.mako @@ -0,0 +1,226 @@ +// This file is auto-generated. Do not edit. +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl::transactions { + +class ${name}Builder; + +/** + * @brief Transaction: ${name} + * + * Type: ${tag} (${value}) + * Delegable: ${delegable} + * Amendment: ${amendments} + * Privileges: ${privileges} + * + * Immutable wrapper around STTx providing type-safe field access. + * Use ${name}Builder to construct new transactions. + */ +class ${name} : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ${tag}; + + /** + * @brief Construct a ${name} transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit ${name}(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for ${name}"); + } + } + + // Transaction-specific field getters +% for field in fields: +% if field['typed']: + + /** + * @brief Get ${field['name']} (${field['requirement']}) +% if field.get('supports_mpt'): + * @note This field supports MPT (Multi-Purpose Token) amounts. +% endif +% if field['requirement'] == 'soeREQUIRED': + * @return The field value. +% else: + * @return The field value, or std::nullopt if not present. +% endif + */ +% if field['requirement'] == 'soeREQUIRED': + [[nodiscard]] + ${field['typeData']['return_type']} + get${field['name'][2:]}() const + { + return this->tx_->${field['typeData']['getter_method']}(${field['name']}); + } +% else: + [[nodiscard]] + ${field['typeData']['return_type_optional']} + get${field['name'][2:]}() const + { + if (has${field['name'][2:]}()) + { + return this->tx_->${field['typeData']['getter_method']}(${field['name']}); + } + return std::nullopt; + } + + /** + * @brief Check if ${field['name']} is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + has${field['name'][2:]}() const + { + return this->tx_->isFieldPresent(${field['name']}); + } +% endif +% else: + /** + * @brief Get ${field['name']} (${field['requirement']}) +% if field.get('supports_mpt'): + * @note This field supports MPT (Multi-Purpose Token) amounts. +% endif + * @note This is an untyped field. +% if field['requirement'] == 'soeREQUIRED': + * @return The field value. +% else: + * @return The field value, or std::nullopt if not present. +% endif + */ +% if field['requirement'] == 'soeREQUIRED': + [[nodiscard]] + ${field['typeData']['return_type']} + get${field['name'][2:]}() const + { + return this->tx_->${field['typeData']['getter_method']}(${field['name']}); + } +% else: + [[nodiscard]] + ${field['typeData']['return_type_optional']} + get${field['name'][2:]}() const + { + if (this->tx_->isFieldPresent(${field['name']})) + return this->tx_->${field['typeData']['getter_method']}(${field['name']}); + return std::nullopt; + } + + /** + * @brief Check if ${field['name']} is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + has${field['name'][2:]}() const + { + return this->tx_->isFieldPresent(${field['name']}); + } +% endif +% endif +% endfor +}; + +<% + required_fields = [f for f in fields if f['requirement'] == 'soeREQUIRED'] +%>\ +/** + * @brief Builder for ${name} transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses Json::Value internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class ${name}Builder : public TransactionBuilderBase<${name}Builder> +{ +public: + /** + * @brief Construct a new ${name}Builder with required fields. + * @param account The account initiating the transaction. +% for field in required_fields: + * @param ${field['paramName']} The ${field['name']} field value. +% endfor + * @param sequence Optional sequence number for the transaction. + * @param fee Optional fee for the transaction. + */ + ${name}Builder(SF_ACCOUNT::type::value_type account, +% for i, field in enumerate(required_fields): + ${field['typeData']['setter_type']} ${field['paramName']},\ +% endfor + std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase<${name}Builder>(${tag}, account, sequence, fee) + { +% for field in required_fields: + set${field['name'][2:]}(${field['paramName']}); +% endfor + } + + /** + * @brief Construct a ${name}Builder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + ${name}Builder(std::shared_ptr tx) + { + if (tx->getTxnType() != ${tag}) + { + throw std::runtime_error("Invalid transaction type for ${name}Builder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ +% for field in fields: + + /** + * @brief Set ${field['name']} (${field['requirement']}) +% if field.get('supports_mpt'): + * @note This field supports MPT (Multi-Purpose Token) amounts. +% endif + * @return Reference to this builder for method chaining. + */ + ${name}Builder& + set${field['name'][2:]}(${field['typeData']['setter_type']} value) + { +% if field.get('stiSuffix') == 'ISSUE': + object_[${field['name']}] = STIssue(${field['name']}, value); +% elif field['typeData'].get('setter_use_brackets'): + object_[${field['name']}] = value; +% else: + object_.${field['typeData']['setter_method']}(${field['name']}, value); +% endif + return *this; + } +% endfor + + /** + * @brief Build and return the ${name} wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + ${name} + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return ${name}{std::make_shared(std::move(object_))}; + } +}; + +} // namespace xrpl::transactions diff --git a/scripts/templates/TransactionTests.cpp.mako b/scripts/templates/TransactionTests.cpp.mako new file mode 100644 index 0000000000..b6bd5cd831 --- /dev/null +++ b/scripts/templates/TransactionTests.cpp.mako @@ -0,0 +1,241 @@ +// Auto-generated unit tests for transaction ${name} +<% + required_fields = [f for f in fields if f["requirement"] == "soeREQUIRED"] + optional_fields = [f for f in fields if f["requirement"] != "soeREQUIRED"] + + def canonical_expr(field): + return f"canonical_{field['stiSuffix']}()" + + # Pick a wrong transaction to test type mismatch + if name != "AccountSet": + wrong_tx_include = "AccountSet" + else: + wrong_tx_include = "OfferCancel" +%> + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(Transactions${name}Tests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("test${name}")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values +% for field in fields: + auto const ${field["paramName"]}Value = ${canonical_expr(field)}; +% endfor + + ${name}Builder builder{ + accountValue, +% for field in required_fields: + ${field["paramName"]}Value, +% endfor + sequenceValue, + feeValue + }; + + // Set optional fields +% for field in optional_fields: + builder.set${field["name"][2:]}(${field["paramName"]}Value); +% endfor + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields +% for field in required_fields: + { + auto const& expected = ${field["paramName"]}Value; + auto const actual = tx.get${field["name"][2:]}(); + expectEqualField(expected, actual, "${field["name"]}"); + } + +% endfor + // Verify optional fields +% for field in optional_fields: + { + auto const& expected = ${field["paramName"]}Value; + auto const actualOpt = tx.get${field["name"][2:]}(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field ${field["name"]} should be present"; + expectEqualField(expected, *actualOpt, "${field["name"]}"); + EXPECT_TRUE(tx.has${field["name"][2:]}()); + } + +% endfor +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(Transactions${name}Tests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("test${name}FromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values +% for field in fields: + auto const ${field["paramName"]}Value = ${canonical_expr(field)}; +% endfor + + // Build an initial transaction + ${name}Builder initialBuilder{ + accountValue, +% for field in required_fields: + ${field["paramName"]}Value, +% endfor + sequenceValue, + feeValue + }; + +% for field in optional_fields: + initialBuilder.set${field["name"][2:]}(${field["paramName"]}Value); +% endfor + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + ${name}Builder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields +% for field in required_fields: + { + auto const& expected = ${field["paramName"]}Value; + auto const actual = rebuiltTx.get${field["name"][2:]}(); + expectEqualField(expected, actual, "${field["name"]}"); + } + +% endfor + // Verify optional fields +% for field in optional_fields: + { + auto const& expected = ${field["paramName"]}Value; + auto const actualOpt = rebuiltTx.get${field["name"][2:]}(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field ${field["name"]} should be present"; + expectEqualField(expected, *actualOpt, "${field["name"]}"); + } + +% endfor +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(Transactions${name}Tests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + +% if wrong_tx_include == "AccountSet": + ${wrong_tx_include}Builder wrongBuilder{account, 1, canonical_AMOUNT()}; +% else: + ${wrong_tx_include}Builder wrongBuilder{account, canonical_UINT32(), 1, canonical_AMOUNT()}; +% endif + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(${name}{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(Transactions${name}Tests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + +% if wrong_tx_include == "AccountSet": + ${wrong_tx_include}Builder wrongBuilder{account, 1, canonical_AMOUNT()}; +% else: + ${wrong_tx_include}Builder wrongBuilder{account, canonical_UINT32(), 1, canonical_AMOUNT()}; +% endif + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(${name}Builder{wrongTx.getSTTx()}, std::runtime_error); +} + +% if optional_fields: +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(Transactions${name}Tests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("test${name}Nullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values +% for field in required_fields: + auto const ${field["paramName"]}Value = ${canonical_expr(field)}; +% endfor + + ${name}Builder builder{ + accountValue, +% for field in required_fields: + ${field["paramName"]}Value, +% endfor + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present +% for field in optional_fields: + EXPECT_FALSE(tx.has${field["name"][2:]}()); + EXPECT_FALSE(tx.get${field["name"][2:]}().has_value()); +% endfor +} +% endif + +} diff --git a/src/libxrpl/protocol_autogen/placeholder.cpp b/src/libxrpl/protocol_autogen/placeholder.cpp new file mode 100644 index 0000000000..b48581e5b8 --- /dev/null +++ b/src/libxrpl/protocol_autogen/placeholder.cpp @@ -0,0 +1,5 @@ +// This file is a placeholder to ensure the protocol_autogen module can be built. +#include +#include +#include +#include diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 6bcb6aff89..a82ed1472f 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -32,6 +32,21 @@ xrpl_add_test(json) target_link_libraries(xrpl.test.json PRIVATE xrpl.imports.test) add_dependencies(xrpl.tests xrpl.test.json) +# protocol_autogen tests use explicit source list (not GLOB) because sources are generated +# Mark generated sources so CMake knows they'll be created at build time +set_source_files_properties( + ${PROTOCOL_AUTOGEN_TEST_SOURCES} + PROPERTIES GENERATED TRUE +) +add_executable(xrpl.test.protocol_autogen ${PROTOCOL_AUTOGEN_TEST_SOURCES}) +target_link_libraries(xrpl.test.protocol_autogen PRIVATE xrpl.imports.test) +add_dependencies(xrpl.tests xrpl.test.protocol_autogen) +add_test(NAME xrpl.test.protocol_autogen COMMAND xrpl.test.protocol_autogen) +# Ensure code generation runs before compiling tests +if(TARGET protocol_autogen_generate) + add_dependencies(xrpl.test.protocol_autogen protocol_autogen_generate) +endif() + # Network unit tests are currently not supported on Windows if(NOT WIN32) xrpl_add_test(net) diff --git a/src/tests/libxrpl/protocol_autogen/STObjectValidation.cpp b/src/tests/libxrpl/protocol_autogen/STObjectValidation.cpp new file mode 100644 index 0000000000..5c100364dc --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/STObjectValidation.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include + +namespace xrpl { +TEST(STObjectValidation, validate_required_field) +{ + SOTemplate format{{sfFlags, soeREQUIRED}}; + STObject obj(sfGeneric); + obj.setFieldU32(sfFlags, 0); + EXPECT_TRUE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_missing_required_field) +{ + SOTemplate format{{sfFlags, soeREQUIRED}}; + STObject obj(sfGeneric); + EXPECT_FALSE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_optional_field) +{ + SOTemplate format{{sfFlags, soeOPTIONAL}}; + STObject obj(sfGeneric); + obj.setFieldU32(sfFlags, 0); + EXPECT_TRUE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_missing_optional_field) +{ + SOTemplate format{{sfFlags, soeOPTIONAL}}; + STObject obj(sfGeneric); + EXPECT_TRUE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_mpt_amount_supported) +{ + SOTemplate format{{sfAmount, soeREQUIRED, soeMPTSupported}}; + STObject obj(sfGeneric); + obj.setFieldAmount(sfAmount, STAmount{MPTAmount{Number{1}}, MPTIssue{}}); + EXPECT_TRUE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_mpt_amount_not_supported) +{ + SOTemplate format{{sfAmount, soeREQUIRED, soeMPTNotSupported}}; + STObject obj(sfGeneric); + obj.setFieldAmount(sfAmount, STAmount{MPTAmount{Number{1}}, MPTIssue{}}); + EXPECT_FALSE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_mpt_issue_supported) +{ + SOTemplate format{{sfAsset, soeREQUIRED, soeMPTSupported}}; + STObject obj(sfGeneric); + obj.setFieldIssue(sfAsset, STIssue{sfAsset, MPTIssue{}}); + EXPECT_TRUE(protocol_autogen::validateSTObject(obj, format)); +} + +TEST(STObjectValidation, validate_mpt_issue_not_supported) +{ + SOTemplate format{{sfAsset, soeREQUIRED, soeMPTNotSupported}}; + STObject obj(sfGeneric); + obj.setFieldIssue(sfAsset, STIssue{sfAsset, MPTIssue{}}); + EXPECT_FALSE(protocol_autogen::validateSTObject(obj, format)); +} +} // namespace xrpl diff --git a/src/tests/libxrpl/protocol_autogen/TestHelpers.h b/src/tests/libxrpl/protocol_autogen/TestHelpers.h new file mode 100644 index 0000000000..cf2d7ffe6a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/TestHelpers.h @@ -0,0 +1,209 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace xrpl { + +// Typed field canonical values + +using Uint8Value = std::decay_t; +inline Uint8Value +canonical_UINT8() +{ + return Uint8Value{1}; +} + +using Uint16Value = std::decay_t; +inline Uint16Value +canonical_UINT16() +{ + return Uint16Value{1}; +} + +using Uint32Value = std::decay_t; +inline Uint32Value +canonical_UINT32() +{ + return Uint32Value{1}; +} + +using Uint64Value = std::decay_t; +inline Uint64Value +canonical_UINT64() +{ + return Uint64Value{1}; +} + +using Uint128Value = std::decay_t; +inline Uint128Value +canonical_UINT128() +{ + return Uint128Value{1}; +} + +using Uint160Value = std::decay_t; +inline Uint160Value +canonical_UINT160() +{ + return Uint160Value{1}; +} + +using Uint192Value = std::decay_t; +inline Uint192Value +canonical_UINT192() +{ + return Uint192Value{1}; +} + +using Uint256Value = std::decay_t; +inline Uint256Value +canonical_UINT256() +{ + return Uint256Value{1}; +} + +using Int32Value = std::decay_t; +inline Int32Value +canonical_INT32() +{ + return Int32Value{42}; +} + +using NumberValue = std::decay_t; +inline NumberValue +canonical_NUMBER() +{ + return NumberValue{123}; +} + +using AmountValue = std::decay_t; +inline AmountValue +canonical_AMOUNT() +{ + return AmountValue{XRPAmount{1}}; +} + +using AccountValue = std::decay_t; +inline AccountValue +canonical_ACCOUNT() +{ + return xrpAccount(); +} + +using CurrencyValue = std::decay_t; +inline CurrencyValue +canonical_CURRENCY() +{ + return xrpCurrency(); +} + +using IssueValue = std::decay_t; +inline IssueValue +canonical_ISSUE() +{ + return IssueValue{xrpIssue()}; +} + +using Vector256Value = std::decay_t; +inline Vector256Value +canonical_VECTOR256() +{ + return Vector256Value{uint256{1}}; +} + +using BlobValue = std::decay_t; +inline BlobValue +canonical_VL() +{ + static constexpr std::array data{{'a', 'b', 'c'}}; + return BlobValue{data.data(), data.size()}; +} + +using XChainBridgeValue = std::decay_t; +inline XChainBridgeValue +canonical_XCHAIN_BRIDGE() +{ + return XChainBridgeValue{xrpAccount(), xrpIssue(), xrpAccount(), xrpIssue()}; +} + +// Untyped field canonical values + +inline STArray +canonical_ARRAY() +{ + return STArray{}; +} + +inline STObject +canonical_OBJECT() +{ + return STObject{sfGeneric}; +} + +inline STPathSet +canonical_PATHSET() +{ + STPathSet result{}; + result.push_back(STPath{}); + return result; +} + +// Field comparison helpers for generated tests + +template +void +expectEqualField(T const& expected, T const& actual, char const* fieldName) +{ + EXPECT_EQ(expected, actual) << "Field " << fieldName << " mismatch"; +} + +// Specialization for STObject (no operator==, use isEquivalent) +template <> +inline void +expectEqualField(STObject const& expected, STObject const& actual, char const* fieldName) +{ + EXPECT_TRUE(expected.isEquivalent(actual)) << "Field " << fieldName << " mismatch"; +} + +// Specialization for STPathSet (no operator==, use isEquivalent) +template <> +inline void +expectEqualField( + STPathSet const& expected, + STPathSet const& actual, + char const* fieldName) +{ + EXPECT_TRUE(expected.isEquivalent(actual)) << "Field " << fieldName << " mismatch"; +} + +// Overloads for std::reference_wrapper (used by optional ARRAY/PATHSET fields) +template +void +expectEqualField(T const& expected, std::reference_wrapper actual, char const* fieldName) +{ + expectEqualField(expected, actual.get(), fieldName); +} + +} // namespace xrpl diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/AMMTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/AMMTests.cpp new file mode 100644 index 0000000000..0bb80c41e6 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/AMMTests.cpp @@ -0,0 +1,361 @@ +// Auto-generated unit tests for ledger entry AMM + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(AMMTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const tradingFeeValue = canonical_UINT16(); + auto const voteSlotsValue = canonical_ARRAY(); + auto const auctionSlotValue = canonical_OBJECT(); + auto const lPTokenBalanceValue = canonical_AMOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + AMMBuilder builder{ + accountValue, + lPTokenBalanceValue, + assetValue, + asset2Value, + ownerNodeValue + }; + + builder.setTradingFee(tradingFeeValue); + builder.setVoteSlots(voteSlotsValue); + builder.setAuctionSlot(auctionSlotValue); + builder.setPreviousTxnID(previousTxnIDValue); + builder.setPreviousTxnLgrSeq(previousTxnLgrSeqValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = lPTokenBalanceValue; + auto const actual = entry.getLPTokenBalance(); + expectEqualField(expected, actual, "sfLPTokenBalance"); + } + + { + auto const& expected = assetValue; + auto const actual = entry.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = entry.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = tradingFeeValue; + auto const actualOpt = entry.getTradingFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTradingFee"); + EXPECT_TRUE(entry.hasTradingFee()); + } + + { + auto const& expected = voteSlotsValue; + auto const actualOpt = entry.getVoteSlots(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfVoteSlots"); + EXPECT_TRUE(entry.hasVoteSlots()); + } + + { + auto const& expected = auctionSlotValue; + auto const actualOpt = entry.getAuctionSlot(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAuctionSlot"); + EXPECT_TRUE(entry.hasAuctionSlot()); + } + + { + auto const& expected = previousTxnIDValue; + auto const actualOpt = entry.getPreviousTxnID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnID"); + EXPECT_TRUE(entry.hasPreviousTxnID()); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actualOpt = entry.getPreviousTxnLgrSeq(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnLgrSeq"); + EXPECT_TRUE(entry.hasPreviousTxnLgrSeq()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(AMMTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const tradingFeeValue = canonical_UINT16(); + auto const voteSlotsValue = canonical_ARRAY(); + auto const auctionSlotValue = canonical_OBJECT(); + auto const lPTokenBalanceValue = canonical_AMOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(AMM::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfTradingFee) = tradingFeeValue; + sle->setFieldArray(sfVoteSlots, voteSlotsValue); + sle->setFieldObject(sfAuctionSlot, auctionSlotValue); + sle->at(sfLPTokenBalance) = lPTokenBalanceValue; + sle->at(sfAsset) = STIssue(sfAsset, assetValue); + sle->at(sfAsset2) = STIssue(sfAsset2, asset2Value); + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + AMMBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + AMM entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = lPTokenBalanceValue; + + auto const fromSle = entryFromSle.getLPTokenBalance(); + auto const fromBuilder = entryFromBuilder.getLPTokenBalance(); + + expectEqualField(expected, fromSle, "sfLPTokenBalance"); + expectEqualField(expected, fromBuilder, "sfLPTokenBalance"); + } + + { + auto const& expected = assetValue; + + auto const fromSle = entryFromSle.getAsset(); + auto const fromBuilder = entryFromBuilder.getAsset(); + + expectEqualField(expected, fromSle, "sfAsset"); + expectEqualField(expected, fromBuilder, "sfAsset"); + } + + { + auto const& expected = asset2Value; + + auto const fromSle = entryFromSle.getAsset2(); + auto const fromBuilder = entryFromBuilder.getAsset2(); + + expectEqualField(expected, fromSle, "sfAsset2"); + expectEqualField(expected, fromBuilder, "sfAsset2"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = tradingFeeValue; + + auto const fromSleOpt = entryFromSle.getTradingFee(); + auto const fromBuilderOpt = entryFromBuilder.getTradingFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTradingFee"); + expectEqualField(expected, *fromBuilderOpt, "sfTradingFee"); + } + + { + auto const& expected = voteSlotsValue; + + auto const fromSleOpt = entryFromSle.getVoteSlots(); + auto const fromBuilderOpt = entryFromBuilder.getVoteSlots(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfVoteSlots"); + expectEqualField(expected, *fromBuilderOpt, "sfVoteSlots"); + } + + { + auto const& expected = auctionSlotValue; + + auto const fromSleOpt = entryFromSle.getAuctionSlot(); + auto const fromBuilderOpt = entryFromBuilder.getAuctionSlot(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAuctionSlot"); + expectEqualField(expected, *fromBuilderOpt, "sfAuctionSlot"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnID(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnID"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnLgrSeq(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(AMMTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(AMM{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(AMMTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(AMMBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(AMMTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const lPTokenBalanceValue = canonical_AMOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const ownerNodeValue = canonical_UINT64(); + + AMMBuilder builder{ + accountValue, + lPTokenBalanceValue, + assetValue, + asset2Value, + ownerNodeValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasTradingFee()); + EXPECT_FALSE(entry.getTradingFee().has_value()); + EXPECT_FALSE(entry.hasVoteSlots()); + EXPECT_FALSE(entry.getVoteSlots().has_value()); + EXPECT_FALSE(entry.hasAuctionSlot()); + EXPECT_FALSE(entry.getAuctionSlot().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnID()); + EXPECT_FALSE(entry.getPreviousTxnID().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnLgrSeq()); + EXPECT_FALSE(entry.getPreviousTxnLgrSeq().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/AccountRootTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/AccountRootTests.cpp new file mode 100644 index 0000000000..e967b614b7 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/AccountRootTests.cpp @@ -0,0 +1,707 @@ +// Auto-generated unit tests for ledger entry AccountRoot + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(AccountRootTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const balanceValue = canonical_AMOUNT(); + auto const ownerCountValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const accountTxnIDValue = canonical_UINT256(); + auto const regularKeyValue = canonical_ACCOUNT(); + auto const emailHashValue = canonical_UINT128(); + auto const walletLocatorValue = canonical_UINT256(); + auto const walletSizeValue = canonical_UINT32(); + auto const messageKeyValue = canonical_VL(); + auto const transferRateValue = canonical_UINT32(); + auto const domainValue = canonical_VL(); + auto const tickSizeValue = canonical_UINT8(); + auto const ticketCountValue = canonical_UINT32(); + auto const nFTokenMinterValue = canonical_ACCOUNT(); + auto const mintedNFTokensValue = canonical_UINT32(); + auto const burnedNFTokensValue = canonical_UINT32(); + auto const firstNFTokenSequenceValue = canonical_UINT32(); + auto const aMMIDValue = canonical_UINT256(); + auto const vaultIDValue = canonical_UINT256(); + auto const loanBrokerIDValue = canonical_UINT256(); + + AccountRootBuilder builder{ + accountValue, + sequenceValue, + balanceValue, + ownerCountValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setAccountTxnID(accountTxnIDValue); + builder.setRegularKey(regularKeyValue); + builder.setEmailHash(emailHashValue); + builder.setWalletLocator(walletLocatorValue); + builder.setWalletSize(walletSizeValue); + builder.setMessageKey(messageKeyValue); + builder.setTransferRate(transferRateValue); + builder.setDomain(domainValue); + builder.setTickSize(tickSizeValue); + builder.setTicketCount(ticketCountValue); + builder.setNFTokenMinter(nFTokenMinterValue); + builder.setMintedNFTokens(mintedNFTokensValue); + builder.setBurnedNFTokens(burnedNFTokensValue); + builder.setFirstNFTokenSequence(firstNFTokenSequenceValue); + builder.setAMMID(aMMIDValue); + builder.setVaultID(vaultIDValue); + builder.setLoanBrokerID(loanBrokerIDValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = balanceValue; + auto const actual = entry.getBalance(); + expectEqualField(expected, actual, "sfBalance"); + } + + { + auto const& expected = ownerCountValue; + auto const actual = entry.getOwnerCount(); + expectEqualField(expected, actual, "sfOwnerCount"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = accountTxnIDValue; + auto const actualOpt = entry.getAccountTxnID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAccountTxnID"); + EXPECT_TRUE(entry.hasAccountTxnID()); + } + + { + auto const& expected = regularKeyValue; + auto const actualOpt = entry.getRegularKey(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfRegularKey"); + EXPECT_TRUE(entry.hasRegularKey()); + } + + { + auto const& expected = emailHashValue; + auto const actualOpt = entry.getEmailHash(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfEmailHash"); + EXPECT_TRUE(entry.hasEmailHash()); + } + + { + auto const& expected = walletLocatorValue; + auto const actualOpt = entry.getWalletLocator(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfWalletLocator"); + EXPECT_TRUE(entry.hasWalletLocator()); + } + + { + auto const& expected = walletSizeValue; + auto const actualOpt = entry.getWalletSize(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfWalletSize"); + EXPECT_TRUE(entry.hasWalletSize()); + } + + { + auto const& expected = messageKeyValue; + auto const actualOpt = entry.getMessageKey(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMessageKey"); + EXPECT_TRUE(entry.hasMessageKey()); + } + + { + auto const& expected = transferRateValue; + auto const actualOpt = entry.getTransferRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTransferRate"); + EXPECT_TRUE(entry.hasTransferRate()); + } + + { + auto const& expected = domainValue; + auto const actualOpt = entry.getDomain(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDomain"); + EXPECT_TRUE(entry.hasDomain()); + } + + { + auto const& expected = tickSizeValue; + auto const actualOpt = entry.getTickSize(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTickSize"); + EXPECT_TRUE(entry.hasTickSize()); + } + + { + auto const& expected = ticketCountValue; + auto const actualOpt = entry.getTicketCount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTicketCount"); + EXPECT_TRUE(entry.hasTicketCount()); + } + + { + auto const& expected = nFTokenMinterValue; + auto const actualOpt = entry.getNFTokenMinter(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfNFTokenMinter"); + EXPECT_TRUE(entry.hasNFTokenMinter()); + } + + { + auto const& expected = mintedNFTokensValue; + auto const actualOpt = entry.getMintedNFTokens(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMintedNFTokens"); + EXPECT_TRUE(entry.hasMintedNFTokens()); + } + + { + auto const& expected = burnedNFTokensValue; + auto const actualOpt = entry.getBurnedNFTokens(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfBurnedNFTokens"); + EXPECT_TRUE(entry.hasBurnedNFTokens()); + } + + { + auto const& expected = firstNFTokenSequenceValue; + auto const actualOpt = entry.getFirstNFTokenSequence(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfFirstNFTokenSequence"); + EXPECT_TRUE(entry.hasFirstNFTokenSequence()); + } + + { + auto const& expected = aMMIDValue; + auto const actualOpt = entry.getAMMID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAMMID"); + EXPECT_TRUE(entry.hasAMMID()); + } + + { + auto const& expected = vaultIDValue; + auto const actualOpt = entry.getVaultID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfVaultID"); + EXPECT_TRUE(entry.hasVaultID()); + } + + { + auto const& expected = loanBrokerIDValue; + auto const actualOpt = entry.getLoanBrokerID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLoanBrokerID"); + EXPECT_TRUE(entry.hasLoanBrokerID()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(AccountRootTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const balanceValue = canonical_AMOUNT(); + auto const ownerCountValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const accountTxnIDValue = canonical_UINT256(); + auto const regularKeyValue = canonical_ACCOUNT(); + auto const emailHashValue = canonical_UINT128(); + auto const walletLocatorValue = canonical_UINT256(); + auto const walletSizeValue = canonical_UINT32(); + auto const messageKeyValue = canonical_VL(); + auto const transferRateValue = canonical_UINT32(); + auto const domainValue = canonical_VL(); + auto const tickSizeValue = canonical_UINT8(); + auto const ticketCountValue = canonical_UINT32(); + auto const nFTokenMinterValue = canonical_ACCOUNT(); + auto const mintedNFTokensValue = canonical_UINT32(); + auto const burnedNFTokensValue = canonical_UINT32(); + auto const firstNFTokenSequenceValue = canonical_UINT32(); + auto const aMMIDValue = canonical_UINT256(); + auto const vaultIDValue = canonical_UINT256(); + auto const loanBrokerIDValue = canonical_UINT256(); + + auto sle = std::make_shared(AccountRoot::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfBalance) = balanceValue; + sle->at(sfOwnerCount) = ownerCountValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfAccountTxnID) = accountTxnIDValue; + sle->at(sfRegularKey) = regularKeyValue; + sle->at(sfEmailHash) = emailHashValue; + sle->at(sfWalletLocator) = walletLocatorValue; + sle->at(sfWalletSize) = walletSizeValue; + sle->at(sfMessageKey) = messageKeyValue; + sle->at(sfTransferRate) = transferRateValue; + sle->at(sfDomain) = domainValue; + sle->at(sfTickSize) = tickSizeValue; + sle->at(sfTicketCount) = ticketCountValue; + sle->at(sfNFTokenMinter) = nFTokenMinterValue; + sle->at(sfMintedNFTokens) = mintedNFTokensValue; + sle->at(sfBurnedNFTokens) = burnedNFTokensValue; + sle->at(sfFirstNFTokenSequence) = firstNFTokenSequenceValue; + sle->at(sfAMMID) = aMMIDValue; + sle->at(sfVaultID) = vaultIDValue; + sle->at(sfLoanBrokerID) = loanBrokerIDValue; + + AccountRootBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + AccountRoot entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = balanceValue; + + auto const fromSle = entryFromSle.getBalance(); + auto const fromBuilder = entryFromBuilder.getBalance(); + + expectEqualField(expected, fromSle, "sfBalance"); + expectEqualField(expected, fromBuilder, "sfBalance"); + } + + { + auto const& expected = ownerCountValue; + + auto const fromSle = entryFromSle.getOwnerCount(); + auto const fromBuilder = entryFromBuilder.getOwnerCount(); + + expectEqualField(expected, fromSle, "sfOwnerCount"); + expectEqualField(expected, fromBuilder, "sfOwnerCount"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = accountTxnIDValue; + + auto const fromSleOpt = entryFromSle.getAccountTxnID(); + auto const fromBuilderOpt = entryFromBuilder.getAccountTxnID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAccountTxnID"); + expectEqualField(expected, *fromBuilderOpt, "sfAccountTxnID"); + } + + { + auto const& expected = regularKeyValue; + + auto const fromSleOpt = entryFromSle.getRegularKey(); + auto const fromBuilderOpt = entryFromBuilder.getRegularKey(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfRegularKey"); + expectEqualField(expected, *fromBuilderOpt, "sfRegularKey"); + } + + { + auto const& expected = emailHashValue; + + auto const fromSleOpt = entryFromSle.getEmailHash(); + auto const fromBuilderOpt = entryFromBuilder.getEmailHash(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfEmailHash"); + expectEqualField(expected, *fromBuilderOpt, "sfEmailHash"); + } + + { + auto const& expected = walletLocatorValue; + + auto const fromSleOpt = entryFromSle.getWalletLocator(); + auto const fromBuilderOpt = entryFromBuilder.getWalletLocator(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfWalletLocator"); + expectEqualField(expected, *fromBuilderOpt, "sfWalletLocator"); + } + + { + auto const& expected = walletSizeValue; + + auto const fromSleOpt = entryFromSle.getWalletSize(); + auto const fromBuilderOpt = entryFromBuilder.getWalletSize(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfWalletSize"); + expectEqualField(expected, *fromBuilderOpt, "sfWalletSize"); + } + + { + auto const& expected = messageKeyValue; + + auto const fromSleOpt = entryFromSle.getMessageKey(); + auto const fromBuilderOpt = entryFromBuilder.getMessageKey(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMessageKey"); + expectEqualField(expected, *fromBuilderOpt, "sfMessageKey"); + } + + { + auto const& expected = transferRateValue; + + auto const fromSleOpt = entryFromSle.getTransferRate(); + auto const fromBuilderOpt = entryFromBuilder.getTransferRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTransferRate"); + expectEqualField(expected, *fromBuilderOpt, "sfTransferRate"); + } + + { + auto const& expected = domainValue; + + auto const fromSleOpt = entryFromSle.getDomain(); + auto const fromBuilderOpt = entryFromBuilder.getDomain(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDomain"); + expectEqualField(expected, *fromBuilderOpt, "sfDomain"); + } + + { + auto const& expected = tickSizeValue; + + auto const fromSleOpt = entryFromSle.getTickSize(); + auto const fromBuilderOpt = entryFromBuilder.getTickSize(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTickSize"); + expectEqualField(expected, *fromBuilderOpt, "sfTickSize"); + } + + { + auto const& expected = ticketCountValue; + + auto const fromSleOpt = entryFromSle.getTicketCount(); + auto const fromBuilderOpt = entryFromBuilder.getTicketCount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTicketCount"); + expectEqualField(expected, *fromBuilderOpt, "sfTicketCount"); + } + + { + auto const& expected = nFTokenMinterValue; + + auto const fromSleOpt = entryFromSle.getNFTokenMinter(); + auto const fromBuilderOpt = entryFromBuilder.getNFTokenMinter(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfNFTokenMinter"); + expectEqualField(expected, *fromBuilderOpt, "sfNFTokenMinter"); + } + + { + auto const& expected = mintedNFTokensValue; + + auto const fromSleOpt = entryFromSle.getMintedNFTokens(); + auto const fromBuilderOpt = entryFromBuilder.getMintedNFTokens(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMintedNFTokens"); + expectEqualField(expected, *fromBuilderOpt, "sfMintedNFTokens"); + } + + { + auto const& expected = burnedNFTokensValue; + + auto const fromSleOpt = entryFromSle.getBurnedNFTokens(); + auto const fromBuilderOpt = entryFromBuilder.getBurnedNFTokens(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfBurnedNFTokens"); + expectEqualField(expected, *fromBuilderOpt, "sfBurnedNFTokens"); + } + + { + auto const& expected = firstNFTokenSequenceValue; + + auto const fromSleOpt = entryFromSle.getFirstNFTokenSequence(); + auto const fromBuilderOpt = entryFromBuilder.getFirstNFTokenSequence(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfFirstNFTokenSequence"); + expectEqualField(expected, *fromBuilderOpt, "sfFirstNFTokenSequence"); + } + + { + auto const& expected = aMMIDValue; + + auto const fromSleOpt = entryFromSle.getAMMID(); + auto const fromBuilderOpt = entryFromBuilder.getAMMID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAMMID"); + expectEqualField(expected, *fromBuilderOpt, "sfAMMID"); + } + + { + auto const& expected = vaultIDValue; + + auto const fromSleOpt = entryFromSle.getVaultID(); + auto const fromBuilderOpt = entryFromBuilder.getVaultID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfVaultID"); + expectEqualField(expected, *fromBuilderOpt, "sfVaultID"); + } + + { + auto const& expected = loanBrokerIDValue; + + auto const fromSleOpt = entryFromSle.getLoanBrokerID(); + auto const fromBuilderOpt = entryFromBuilder.getLoanBrokerID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLoanBrokerID"); + expectEqualField(expected, *fromBuilderOpt, "sfLoanBrokerID"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(AccountRootTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(AccountRoot{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(AccountRootTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(AccountRootBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(AccountRootTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const balanceValue = canonical_AMOUNT(); + auto const ownerCountValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + AccountRootBuilder builder{ + accountValue, + sequenceValue, + balanceValue, + ownerCountValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasAccountTxnID()); + EXPECT_FALSE(entry.getAccountTxnID().has_value()); + EXPECT_FALSE(entry.hasRegularKey()); + EXPECT_FALSE(entry.getRegularKey().has_value()); + EXPECT_FALSE(entry.hasEmailHash()); + EXPECT_FALSE(entry.getEmailHash().has_value()); + EXPECT_FALSE(entry.hasWalletLocator()); + EXPECT_FALSE(entry.getWalletLocator().has_value()); + EXPECT_FALSE(entry.hasWalletSize()); + EXPECT_FALSE(entry.getWalletSize().has_value()); + EXPECT_FALSE(entry.hasMessageKey()); + EXPECT_FALSE(entry.getMessageKey().has_value()); + EXPECT_FALSE(entry.hasTransferRate()); + EXPECT_FALSE(entry.getTransferRate().has_value()); + EXPECT_FALSE(entry.hasDomain()); + EXPECT_FALSE(entry.getDomain().has_value()); + EXPECT_FALSE(entry.hasTickSize()); + EXPECT_FALSE(entry.getTickSize().has_value()); + EXPECT_FALSE(entry.hasTicketCount()); + EXPECT_FALSE(entry.getTicketCount().has_value()); + EXPECT_FALSE(entry.hasNFTokenMinter()); + EXPECT_FALSE(entry.getNFTokenMinter().has_value()); + EXPECT_FALSE(entry.hasMintedNFTokens()); + EXPECT_FALSE(entry.getMintedNFTokens().has_value()); + EXPECT_FALSE(entry.hasBurnedNFTokens()); + EXPECT_FALSE(entry.getBurnedNFTokens().has_value()); + EXPECT_FALSE(entry.hasFirstNFTokenSequence()); + EXPECT_FALSE(entry.getFirstNFTokenSequence().has_value()); + EXPECT_FALSE(entry.hasAMMID()); + EXPECT_FALSE(entry.getAMMID().has_value()); + EXPECT_FALSE(entry.hasVaultID()); + EXPECT_FALSE(entry.getVaultID().has_value()); + EXPECT_FALSE(entry.hasLoanBrokerID()); + EXPECT_FALSE(entry.getLoanBrokerID().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/AmendmentsTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/AmendmentsTests.cpp new file mode 100644 index 0000000000..17da755a3d --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/AmendmentsTests.cpp @@ -0,0 +1,224 @@ +// Auto-generated unit tests for ledger entry Amendments + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(AmendmentsTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const amendmentsValue = canonical_VECTOR256(); + auto const majoritiesValue = canonical_ARRAY(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + AmendmentsBuilder builder{ + }; + + builder.setAmendments(amendmentsValue); + builder.setMajorities(majoritiesValue); + builder.setPreviousTxnID(previousTxnIDValue); + builder.setPreviousTxnLgrSeq(previousTxnLgrSeqValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = amendmentsValue; + auto const actualOpt = entry.getAmendments(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAmendments"); + EXPECT_TRUE(entry.hasAmendments()); + } + + { + auto const& expected = majoritiesValue; + auto const actualOpt = entry.getMajorities(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMajorities"); + EXPECT_TRUE(entry.hasMajorities()); + } + + { + auto const& expected = previousTxnIDValue; + auto const actualOpt = entry.getPreviousTxnID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnID"); + EXPECT_TRUE(entry.hasPreviousTxnID()); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actualOpt = entry.getPreviousTxnLgrSeq(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnLgrSeq"); + EXPECT_TRUE(entry.hasPreviousTxnLgrSeq()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(AmendmentsTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const amendmentsValue = canonical_VECTOR256(); + auto const majoritiesValue = canonical_ARRAY(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Amendments::entryType, index); + + sle->at(sfAmendments) = amendmentsValue; + sle->setFieldArray(sfMajorities, majoritiesValue); + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + AmendmentsBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Amendments entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = amendmentsValue; + + auto const fromSleOpt = entryFromSle.getAmendments(); + auto const fromBuilderOpt = entryFromBuilder.getAmendments(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAmendments"); + expectEqualField(expected, *fromBuilderOpt, "sfAmendments"); + } + + { + auto const& expected = majoritiesValue; + + auto const fromSleOpt = entryFromSle.getMajorities(); + auto const fromBuilderOpt = entryFromBuilder.getMajorities(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMajorities"); + expectEqualField(expected, *fromBuilderOpt, "sfMajorities"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnID(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnID"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnLgrSeq(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(AmendmentsTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Amendments{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(AmendmentsTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(AmendmentsBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(AmendmentsTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + + AmendmentsBuilder builder{ + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasAmendments()); + EXPECT_FALSE(entry.getAmendments().has_value()); + EXPECT_FALSE(entry.hasMajorities()); + EXPECT_FALSE(entry.getMajorities().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnID()); + EXPECT_FALSE(entry.getPreviousTxnID().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnLgrSeq()); + EXPECT_FALSE(entry.getPreviousTxnLgrSeq().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp new file mode 100644 index 0000000000..1d4cfc00b9 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/BridgeTests.cpp @@ -0,0 +1,341 @@ +// Auto-generated unit tests for ledger entry Bridge + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(BridgeTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const minAccountCreateAmountValue = canonical_AMOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const xChainAccountClaimCountValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + BridgeBuilder builder{ + accountValue, + signatureRewardValue, + xChainBridgeValue, + xChainClaimIDValue, + xChainAccountCreateCountValue, + xChainAccountClaimCountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setMinAccountCreateAmount(minAccountCreateAmountValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = entry.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + { + auto const& expected = xChainBridgeValue; + auto const actual = entry.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = entry.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + { + auto const& expected = xChainAccountCreateCountValue; + auto const actual = entry.getXChainAccountCreateCount(); + expectEqualField(expected, actual, "sfXChainAccountCreateCount"); + } + + { + auto const& expected = xChainAccountClaimCountValue; + auto const actual = entry.getXChainAccountClaimCount(); + expectEqualField(expected, actual, "sfXChainAccountClaimCount"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = minAccountCreateAmountValue; + auto const actualOpt = entry.getMinAccountCreateAmount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); + EXPECT_TRUE(entry.hasMinAccountCreateAmount()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(BridgeTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const minAccountCreateAmountValue = canonical_AMOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const xChainAccountClaimCountValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Bridge::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfSignatureReward) = signatureRewardValue; + sle->at(sfMinAccountCreateAmount) = minAccountCreateAmountValue; + sle->at(sfXChainBridge) = xChainBridgeValue; + sle->at(sfXChainClaimID) = xChainClaimIDValue; + sle->at(sfXChainAccountCreateCount) = xChainAccountCreateCountValue; + sle->at(sfXChainAccountClaimCount) = xChainAccountClaimCountValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + BridgeBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Bridge entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = signatureRewardValue; + + auto const fromSle = entryFromSle.getSignatureReward(); + auto const fromBuilder = entryFromBuilder.getSignatureReward(); + + expectEqualField(expected, fromSle, "sfSignatureReward"); + expectEqualField(expected, fromBuilder, "sfSignatureReward"); + } + + { + auto const& expected = xChainBridgeValue; + + auto const fromSle = entryFromSle.getXChainBridge(); + auto const fromBuilder = entryFromBuilder.getXChainBridge(); + + expectEqualField(expected, fromSle, "sfXChainBridge"); + expectEqualField(expected, fromBuilder, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + + auto const fromSle = entryFromSle.getXChainClaimID(); + auto const fromBuilder = entryFromBuilder.getXChainClaimID(); + + expectEqualField(expected, fromSle, "sfXChainClaimID"); + expectEqualField(expected, fromBuilder, "sfXChainClaimID"); + } + + { + auto const& expected = xChainAccountCreateCountValue; + + auto const fromSle = entryFromSle.getXChainAccountCreateCount(); + auto const fromBuilder = entryFromBuilder.getXChainAccountCreateCount(); + + expectEqualField(expected, fromSle, "sfXChainAccountCreateCount"); + expectEqualField(expected, fromBuilder, "sfXChainAccountCreateCount"); + } + + { + auto const& expected = xChainAccountClaimCountValue; + + auto const fromSle = entryFromSle.getXChainAccountClaimCount(); + auto const fromBuilder = entryFromBuilder.getXChainAccountClaimCount(); + + expectEqualField(expected, fromSle, "sfXChainAccountClaimCount"); + expectEqualField(expected, fromBuilder, "sfXChainAccountClaimCount"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = minAccountCreateAmountValue; + + auto const fromSleOpt = entryFromSle.getMinAccountCreateAmount(); + auto const fromBuilderOpt = entryFromBuilder.getMinAccountCreateAmount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMinAccountCreateAmount"); + expectEqualField(expected, *fromBuilderOpt, "sfMinAccountCreateAmount"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(BridgeTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Bridge{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(BridgeTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(BridgeBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(BridgeTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const xChainAccountClaimCountValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + BridgeBuilder builder{ + accountValue, + signatureRewardValue, + xChainBridgeValue, + xChainClaimIDValue, + xChainAccountCreateCountValue, + xChainAccountClaimCountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasMinAccountCreateAmount()); + EXPECT_FALSE(entry.getMinAccountCreateAmount().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/CheckTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/CheckTests.cpp new file mode 100644 index 0000000000..f14b4fb4e4 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/CheckTests.cpp @@ -0,0 +1,400 @@ +// Auto-generated unit tests for ledger entry Check + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(CheckTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const destinationNodeValue = canonical_UINT64(); + auto const expirationValue = canonical_UINT32(); + auto const invoiceIDValue = canonical_UINT256(); + auto const sourceTagValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + CheckBuilder builder{ + accountValue, + destinationValue, + sendMaxValue, + sequenceValue, + ownerNodeValue, + destinationNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setExpiration(expirationValue); + builder.setInvoiceID(invoiceIDValue); + builder.setSourceTag(sourceTagValue); + builder.setDestinationTag(destinationTagValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = destinationValue; + auto const actual = entry.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = sendMaxValue; + auto const actual = entry.getSendMax(); + expectEqualField(expected, actual, "sfSendMax"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = destinationNodeValue; + auto const actual = entry.getDestinationNode(); + expectEqualField(expected, actual, "sfDestinationNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = entry.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(entry.hasExpiration()); + } + + { + auto const& expected = invoiceIDValue; + auto const actualOpt = entry.getInvoiceID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfInvoiceID"); + EXPECT_TRUE(entry.hasInvoiceID()); + } + + { + auto const& expected = sourceTagValue; + auto const actualOpt = entry.getSourceTag(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfSourceTag"); + EXPECT_TRUE(entry.hasSourceTag()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = entry.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(entry.hasDestinationTag()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(CheckTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const destinationNodeValue = canonical_UINT64(); + auto const expirationValue = canonical_UINT32(); + auto const invoiceIDValue = canonical_UINT256(); + auto const sourceTagValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Check::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfDestination) = destinationValue; + sle->at(sfSendMax) = sendMaxValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfDestinationNode) = destinationNodeValue; + sle->at(sfExpiration) = expirationValue; + sle->at(sfInvoiceID) = invoiceIDValue; + sle->at(sfSourceTag) = sourceTagValue; + sle->at(sfDestinationTag) = destinationTagValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + CheckBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Check entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = destinationValue; + + auto const fromSle = entryFromSle.getDestination(); + auto const fromBuilder = entryFromBuilder.getDestination(); + + expectEqualField(expected, fromSle, "sfDestination"); + expectEqualField(expected, fromBuilder, "sfDestination"); + } + + { + auto const& expected = sendMaxValue; + + auto const fromSle = entryFromSle.getSendMax(); + auto const fromBuilder = entryFromBuilder.getSendMax(); + + expectEqualField(expected, fromSle, "sfSendMax"); + expectEqualField(expected, fromBuilder, "sfSendMax"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = destinationNodeValue; + + auto const fromSle = entryFromSle.getDestinationNode(); + auto const fromBuilder = entryFromBuilder.getDestinationNode(); + + expectEqualField(expected, fromSle, "sfDestinationNode"); + expectEqualField(expected, fromBuilder, "sfDestinationNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = expirationValue; + + auto const fromSleOpt = entryFromSle.getExpiration(); + auto const fromBuilderOpt = entryFromBuilder.getExpiration(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfExpiration"); + expectEqualField(expected, *fromBuilderOpt, "sfExpiration"); + } + + { + auto const& expected = invoiceIDValue; + + auto const fromSleOpt = entryFromSle.getInvoiceID(); + auto const fromBuilderOpt = entryFromBuilder.getInvoiceID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfInvoiceID"); + expectEqualField(expected, *fromBuilderOpt, "sfInvoiceID"); + } + + { + auto const& expected = sourceTagValue; + + auto const fromSleOpt = entryFromSle.getSourceTag(); + auto const fromBuilderOpt = entryFromBuilder.getSourceTag(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfSourceTag"); + expectEqualField(expected, *fromBuilderOpt, "sfSourceTag"); + } + + { + auto const& expected = destinationTagValue; + + auto const fromSleOpt = entryFromSle.getDestinationTag(); + auto const fromBuilderOpt = entryFromBuilder.getDestinationTag(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDestinationTag"); + expectEqualField(expected, *fromBuilderOpt, "sfDestinationTag"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(CheckTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Check{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(CheckTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(CheckBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(CheckTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const destinationNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + CheckBuilder builder{ + accountValue, + destinationValue, + sendMaxValue, + sequenceValue, + ownerNodeValue, + destinationNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasExpiration()); + EXPECT_FALSE(entry.getExpiration().has_value()); + EXPECT_FALSE(entry.hasInvoiceID()); + EXPECT_FALSE(entry.getInvoiceID().has_value()); + EXPECT_FALSE(entry.hasSourceTag()); + EXPECT_FALSE(entry.getSourceTag().has_value()); + EXPECT_FALSE(entry.hasDestinationTag()); + EXPECT_FALSE(entry.getDestinationTag().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/CredentialTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/CredentialTests.cpp new file mode 100644 index 0000000000..4fbf6d2a26 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/CredentialTests.cpp @@ -0,0 +1,329 @@ +// Auto-generated unit tests for ledger entry Credential + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(CredentialTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const subjectValue = canonical_ACCOUNT(); + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + auto const expirationValue = canonical_UINT32(); + auto const uRIValue = canonical_VL(); + auto const issuerNodeValue = canonical_UINT64(); + auto const subjectNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + CredentialBuilder builder{ + subjectValue, + issuerValue, + credentialTypeValue, + issuerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setExpiration(expirationValue); + builder.setURI(uRIValue); + builder.setSubjectNode(subjectNodeValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = subjectValue; + auto const actual = entry.getSubject(); + expectEqualField(expected, actual, "sfSubject"); + } + + { + auto const& expected = issuerValue; + auto const actual = entry.getIssuer(); + expectEqualField(expected, actual, "sfIssuer"); + } + + { + auto const& expected = credentialTypeValue; + auto const actual = entry.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + { + auto const& expected = issuerNodeValue; + auto const actual = entry.getIssuerNode(); + expectEqualField(expected, actual, "sfIssuerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = entry.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(entry.hasExpiration()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = entry.getURI(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(entry.hasURI()); + } + + { + auto const& expected = subjectNodeValue; + auto const actualOpt = entry.getSubjectNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfSubjectNode"); + EXPECT_TRUE(entry.hasSubjectNode()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(CredentialTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const subjectValue = canonical_ACCOUNT(); + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + auto const expirationValue = canonical_UINT32(); + auto const uRIValue = canonical_VL(); + auto const issuerNodeValue = canonical_UINT64(); + auto const subjectNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Credential::entryType, index); + + sle->at(sfSubject) = subjectValue; + sle->at(sfIssuer) = issuerValue; + sle->at(sfCredentialType) = credentialTypeValue; + sle->at(sfExpiration) = expirationValue; + sle->at(sfURI) = uRIValue; + sle->at(sfIssuerNode) = issuerNodeValue; + sle->at(sfSubjectNode) = subjectNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + CredentialBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Credential entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = subjectValue; + + auto const fromSle = entryFromSle.getSubject(); + auto const fromBuilder = entryFromBuilder.getSubject(); + + expectEqualField(expected, fromSle, "sfSubject"); + expectEqualField(expected, fromBuilder, "sfSubject"); + } + + { + auto const& expected = issuerValue; + + auto const fromSle = entryFromSle.getIssuer(); + auto const fromBuilder = entryFromBuilder.getIssuer(); + + expectEqualField(expected, fromSle, "sfIssuer"); + expectEqualField(expected, fromBuilder, "sfIssuer"); + } + + { + auto const& expected = credentialTypeValue; + + auto const fromSle = entryFromSle.getCredentialType(); + auto const fromBuilder = entryFromBuilder.getCredentialType(); + + expectEqualField(expected, fromSle, "sfCredentialType"); + expectEqualField(expected, fromBuilder, "sfCredentialType"); + } + + { + auto const& expected = issuerNodeValue; + + auto const fromSle = entryFromSle.getIssuerNode(); + auto const fromBuilder = entryFromBuilder.getIssuerNode(); + + expectEqualField(expected, fromSle, "sfIssuerNode"); + expectEqualField(expected, fromBuilder, "sfIssuerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = expirationValue; + + auto const fromSleOpt = entryFromSle.getExpiration(); + auto const fromBuilderOpt = entryFromBuilder.getExpiration(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfExpiration"); + expectEqualField(expected, *fromBuilderOpt, "sfExpiration"); + } + + { + auto const& expected = uRIValue; + + auto const fromSleOpt = entryFromSle.getURI(); + auto const fromBuilderOpt = entryFromBuilder.getURI(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfURI"); + expectEqualField(expected, *fromBuilderOpt, "sfURI"); + } + + { + auto const& expected = subjectNodeValue; + + auto const fromSleOpt = entryFromSle.getSubjectNode(); + auto const fromBuilderOpt = entryFromBuilder.getSubjectNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfSubjectNode"); + expectEqualField(expected, *fromBuilderOpt, "sfSubjectNode"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(CredentialTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Credential{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(CredentialTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(CredentialBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(CredentialTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const subjectValue = canonical_ACCOUNT(); + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + auto const issuerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + CredentialBuilder builder{ + subjectValue, + issuerValue, + credentialTypeValue, + issuerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasExpiration()); + EXPECT_FALSE(entry.getExpiration().has_value()); + EXPECT_FALSE(entry.hasURI()); + EXPECT_FALSE(entry.getURI().has_value()); + EXPECT_FALSE(entry.hasSubjectNode()); + EXPECT_FALSE(entry.getSubjectNode().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/DIDTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/DIDTests.cpp new file mode 100644 index 0000000000..29d49a47f2 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/DIDTests.cpp @@ -0,0 +1,285 @@ +// Auto-generated unit tests for ledger entry DID + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(DIDTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const dIDDocumentValue = canonical_VL(); + auto const uRIValue = canonical_VL(); + auto const dataValue = canonical_VL(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + DIDBuilder builder{ + accountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setDIDDocument(dIDDocumentValue); + builder.setURI(uRIValue); + builder.setData(dataValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = dIDDocumentValue; + auto const actualOpt = entry.getDIDDocument(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDIDDocument"); + EXPECT_TRUE(entry.hasDIDDocument()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = entry.getURI(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(entry.hasURI()); + } + + { + auto const& expected = dataValue; + auto const actualOpt = entry.getData(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(entry.hasData()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(DIDTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const dIDDocumentValue = canonical_VL(); + auto const uRIValue = canonical_VL(); + auto const dataValue = canonical_VL(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(DID::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfDIDDocument) = dIDDocumentValue; + sle->at(sfURI) = uRIValue; + sle->at(sfData) = dataValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + DIDBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + DID entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = dIDDocumentValue; + + auto const fromSleOpt = entryFromSle.getDIDDocument(); + auto const fromBuilderOpt = entryFromBuilder.getDIDDocument(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDIDDocument"); + expectEqualField(expected, *fromBuilderOpt, "sfDIDDocument"); + } + + { + auto const& expected = uRIValue; + + auto const fromSleOpt = entryFromSle.getURI(); + auto const fromBuilderOpt = entryFromBuilder.getURI(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfURI"); + expectEqualField(expected, *fromBuilderOpt, "sfURI"); + } + + { + auto const& expected = dataValue; + + auto const fromSleOpt = entryFromSle.getData(); + auto const fromBuilderOpt = entryFromBuilder.getData(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfData"); + expectEqualField(expected, *fromBuilderOpt, "sfData"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(DIDTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DID{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(DIDTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DIDBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(DIDTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + DIDBuilder builder{ + accountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasDIDDocument()); + EXPECT_FALSE(entry.getDIDDocument().has_value()); + EXPECT_FALSE(entry.hasURI()); + EXPECT_FALSE(entry.getURI().has_value()); + EXPECT_FALSE(entry.hasData()); + EXPECT_FALSE(entry.getData().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/DelegateTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/DelegateTests.cpp new file mode 100644 index 0000000000..68d0e6c08e --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/DelegateTests.cpp @@ -0,0 +1,223 @@ +// Auto-generated unit tests for ledger entry Delegate + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(DelegateTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const authorizeValue = canonical_ACCOUNT(); + auto const permissionsValue = canonical_ARRAY(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + DelegateBuilder builder{ + accountValue, + authorizeValue, + permissionsValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = authorizeValue; + auto const actual = entry.getAuthorize(); + expectEqualField(expected, actual, "sfAuthorize"); + } + + { + auto const& expected = permissionsValue; + auto const actual = entry.getPermissions(); + expectEqualField(expected, actual, "sfPermissions"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(DelegateTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const authorizeValue = canonical_ACCOUNT(); + auto const permissionsValue = canonical_ARRAY(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Delegate::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfAuthorize) = authorizeValue; + sle->setFieldArray(sfPermissions, permissionsValue); + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + DelegateBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Delegate entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = authorizeValue; + + auto const fromSle = entryFromSle.getAuthorize(); + auto const fromBuilder = entryFromBuilder.getAuthorize(); + + expectEqualField(expected, fromSle, "sfAuthorize"); + expectEqualField(expected, fromBuilder, "sfAuthorize"); + } + + { + auto const& expected = permissionsValue; + + auto const fromSle = entryFromSle.getPermissions(); + auto const fromBuilder = entryFromBuilder.getPermissions(); + + expectEqualField(expected, fromSle, "sfPermissions"); + expectEqualField(expected, fromBuilder, "sfPermissions"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(DelegateTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Delegate{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(DelegateTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DelegateBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/DepositPreauthTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/DepositPreauthTests.cpp new file mode 100644 index 0000000000..9e6144d5b9 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/DepositPreauthTests.cpp @@ -0,0 +1,258 @@ +// Auto-generated unit tests for ledger entry DepositPreauth + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(DepositPreauthTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const authorizeValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const authorizeCredentialsValue = canonical_ARRAY(); + + DepositPreauthBuilder builder{ + accountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setAuthorize(authorizeValue); + builder.setAuthorizeCredentials(authorizeCredentialsValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = authorizeValue; + auto const actualOpt = entry.getAuthorize(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAuthorize"); + EXPECT_TRUE(entry.hasAuthorize()); + } + + { + auto const& expected = authorizeCredentialsValue; + auto const actualOpt = entry.getAuthorizeCredentials(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAuthorizeCredentials"); + EXPECT_TRUE(entry.hasAuthorizeCredentials()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(DepositPreauthTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const authorizeValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const authorizeCredentialsValue = canonical_ARRAY(); + + auto sle = std::make_shared(DepositPreauth::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfAuthorize) = authorizeValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->setFieldArray(sfAuthorizeCredentials, authorizeCredentialsValue); + + DepositPreauthBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + DepositPreauth entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = authorizeValue; + + auto const fromSleOpt = entryFromSle.getAuthorize(); + auto const fromBuilderOpt = entryFromBuilder.getAuthorize(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAuthorize"); + expectEqualField(expected, *fromBuilderOpt, "sfAuthorize"); + } + + { + auto const& expected = authorizeCredentialsValue; + + auto const fromSleOpt = entryFromSle.getAuthorizeCredentials(); + auto const fromBuilderOpt = entryFromBuilder.getAuthorizeCredentials(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAuthorizeCredentials"); + expectEqualField(expected, *fromBuilderOpt, "sfAuthorizeCredentials"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(DepositPreauthTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DepositPreauth{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(DepositPreauthTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DepositPreauthBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(DepositPreauthTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + DepositPreauthBuilder builder{ + accountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasAuthorize()); + EXPECT_FALSE(entry.getAuthorize().has_value()); + EXPECT_FALSE(entry.hasAuthorizeCredentials()); + EXPECT_FALSE(entry.getAuthorizeCredentials().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/DirectoryNodeTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/DirectoryNodeTests.cpp new file mode 100644 index 0000000000..d1b6edc704 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/DirectoryNodeTests.cpp @@ -0,0 +1,484 @@ +// Auto-generated unit tests for ledger entry DirectoryNode + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(DirectoryNodeTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const takerPaysCurrencyValue = canonical_UINT160(); + auto const takerPaysIssuerValue = canonical_UINT160(); + auto const takerGetsCurrencyValue = canonical_UINT160(); + auto const takerGetsIssuerValue = canonical_UINT160(); + auto const exchangeRateValue = canonical_UINT64(); + auto const indexesValue = canonical_VECTOR256(); + auto const rootIndexValue = canonical_UINT256(); + auto const indexNextValue = canonical_UINT64(); + auto const indexPreviousValue = canonical_UINT64(); + auto const nFTokenIDValue = canonical_UINT256(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + + DirectoryNodeBuilder builder{ + indexesValue, + rootIndexValue + }; + + builder.setOwner(ownerValue); + builder.setTakerPaysCurrency(takerPaysCurrencyValue); + builder.setTakerPaysIssuer(takerPaysIssuerValue); + builder.setTakerGetsCurrency(takerGetsCurrencyValue); + builder.setTakerGetsIssuer(takerGetsIssuerValue); + builder.setExchangeRate(exchangeRateValue); + builder.setIndexNext(indexNextValue); + builder.setIndexPrevious(indexPreviousValue); + builder.setNFTokenID(nFTokenIDValue); + builder.setPreviousTxnID(previousTxnIDValue); + builder.setPreviousTxnLgrSeq(previousTxnLgrSeqValue); + builder.setDomainID(domainIDValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = indexesValue; + auto const actual = entry.getIndexes(); + expectEqualField(expected, actual, "sfIndexes"); + } + + { + auto const& expected = rootIndexValue; + auto const actual = entry.getRootIndex(); + expectEqualField(expected, actual, "sfRootIndex"); + } + + { + auto const& expected = ownerValue; + auto const actualOpt = entry.getOwner(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOwner"); + EXPECT_TRUE(entry.hasOwner()); + } + + { + auto const& expected = takerPaysCurrencyValue; + auto const actualOpt = entry.getTakerPaysCurrency(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTakerPaysCurrency"); + EXPECT_TRUE(entry.hasTakerPaysCurrency()); + } + + { + auto const& expected = takerPaysIssuerValue; + auto const actualOpt = entry.getTakerPaysIssuer(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTakerPaysIssuer"); + EXPECT_TRUE(entry.hasTakerPaysIssuer()); + } + + { + auto const& expected = takerGetsCurrencyValue; + auto const actualOpt = entry.getTakerGetsCurrency(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTakerGetsCurrency"); + EXPECT_TRUE(entry.hasTakerGetsCurrency()); + } + + { + auto const& expected = takerGetsIssuerValue; + auto const actualOpt = entry.getTakerGetsIssuer(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTakerGetsIssuer"); + EXPECT_TRUE(entry.hasTakerGetsIssuer()); + } + + { + auto const& expected = exchangeRateValue; + auto const actualOpt = entry.getExchangeRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfExchangeRate"); + EXPECT_TRUE(entry.hasExchangeRate()); + } + + { + auto const& expected = indexNextValue; + auto const actualOpt = entry.getIndexNext(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfIndexNext"); + EXPECT_TRUE(entry.hasIndexNext()); + } + + { + auto const& expected = indexPreviousValue; + auto const actualOpt = entry.getIndexPrevious(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfIndexPrevious"); + EXPECT_TRUE(entry.hasIndexPrevious()); + } + + { + auto const& expected = nFTokenIDValue; + auto const actualOpt = entry.getNFTokenID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfNFTokenID"); + EXPECT_TRUE(entry.hasNFTokenID()); + } + + { + auto const& expected = previousTxnIDValue; + auto const actualOpt = entry.getPreviousTxnID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnID"); + EXPECT_TRUE(entry.hasPreviousTxnID()); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actualOpt = entry.getPreviousTxnLgrSeq(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnLgrSeq"); + EXPECT_TRUE(entry.hasPreviousTxnLgrSeq()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = entry.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(entry.hasDomainID()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(DirectoryNodeTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const takerPaysCurrencyValue = canonical_UINT160(); + auto const takerPaysIssuerValue = canonical_UINT160(); + auto const takerGetsCurrencyValue = canonical_UINT160(); + auto const takerGetsIssuerValue = canonical_UINT160(); + auto const exchangeRateValue = canonical_UINT64(); + auto const indexesValue = canonical_VECTOR256(); + auto const rootIndexValue = canonical_UINT256(); + auto const indexNextValue = canonical_UINT64(); + auto const indexPreviousValue = canonical_UINT64(); + auto const nFTokenIDValue = canonical_UINT256(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + + auto sle = std::make_shared(DirectoryNode::entryType, index); + + sle->at(sfOwner) = ownerValue; + sle->at(sfTakerPaysCurrency) = takerPaysCurrencyValue; + sle->at(sfTakerPaysIssuer) = takerPaysIssuerValue; + sle->at(sfTakerGetsCurrency) = takerGetsCurrencyValue; + sle->at(sfTakerGetsIssuer) = takerGetsIssuerValue; + sle->at(sfExchangeRate) = exchangeRateValue; + sle->at(sfIndexes) = indexesValue; + sle->at(sfRootIndex) = rootIndexValue; + sle->at(sfIndexNext) = indexNextValue; + sle->at(sfIndexPrevious) = indexPreviousValue; + sle->at(sfNFTokenID) = nFTokenIDValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfDomainID) = domainIDValue; + + DirectoryNodeBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + DirectoryNode entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = indexesValue; + + auto const fromSle = entryFromSle.getIndexes(); + auto const fromBuilder = entryFromBuilder.getIndexes(); + + expectEqualField(expected, fromSle, "sfIndexes"); + expectEqualField(expected, fromBuilder, "sfIndexes"); + } + + { + auto const& expected = rootIndexValue; + + auto const fromSle = entryFromSle.getRootIndex(); + auto const fromBuilder = entryFromBuilder.getRootIndex(); + + expectEqualField(expected, fromSle, "sfRootIndex"); + expectEqualField(expected, fromBuilder, "sfRootIndex"); + } + + { + auto const& expected = ownerValue; + + auto const fromSleOpt = entryFromSle.getOwner(); + auto const fromBuilderOpt = entryFromBuilder.getOwner(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOwner"); + expectEqualField(expected, *fromBuilderOpt, "sfOwner"); + } + + { + auto const& expected = takerPaysCurrencyValue; + + auto const fromSleOpt = entryFromSle.getTakerPaysCurrency(); + auto const fromBuilderOpt = entryFromBuilder.getTakerPaysCurrency(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTakerPaysCurrency"); + expectEqualField(expected, *fromBuilderOpt, "sfTakerPaysCurrency"); + } + + { + auto const& expected = takerPaysIssuerValue; + + auto const fromSleOpt = entryFromSle.getTakerPaysIssuer(); + auto const fromBuilderOpt = entryFromBuilder.getTakerPaysIssuer(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTakerPaysIssuer"); + expectEqualField(expected, *fromBuilderOpt, "sfTakerPaysIssuer"); + } + + { + auto const& expected = takerGetsCurrencyValue; + + auto const fromSleOpt = entryFromSle.getTakerGetsCurrency(); + auto const fromBuilderOpt = entryFromBuilder.getTakerGetsCurrency(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTakerGetsCurrency"); + expectEqualField(expected, *fromBuilderOpt, "sfTakerGetsCurrency"); + } + + { + auto const& expected = takerGetsIssuerValue; + + auto const fromSleOpt = entryFromSle.getTakerGetsIssuer(); + auto const fromBuilderOpt = entryFromBuilder.getTakerGetsIssuer(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTakerGetsIssuer"); + expectEqualField(expected, *fromBuilderOpt, "sfTakerGetsIssuer"); + } + + { + auto const& expected = exchangeRateValue; + + auto const fromSleOpt = entryFromSle.getExchangeRate(); + auto const fromBuilderOpt = entryFromBuilder.getExchangeRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfExchangeRate"); + expectEqualField(expected, *fromBuilderOpt, "sfExchangeRate"); + } + + { + auto const& expected = indexNextValue; + + auto const fromSleOpt = entryFromSle.getIndexNext(); + auto const fromBuilderOpt = entryFromBuilder.getIndexNext(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfIndexNext"); + expectEqualField(expected, *fromBuilderOpt, "sfIndexNext"); + } + + { + auto const& expected = indexPreviousValue; + + auto const fromSleOpt = entryFromSle.getIndexPrevious(); + auto const fromBuilderOpt = entryFromBuilder.getIndexPrevious(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfIndexPrevious"); + expectEqualField(expected, *fromBuilderOpt, "sfIndexPrevious"); + } + + { + auto const& expected = nFTokenIDValue; + + auto const fromSleOpt = entryFromSle.getNFTokenID(); + auto const fromBuilderOpt = entryFromBuilder.getNFTokenID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfNFTokenID"); + expectEqualField(expected, *fromBuilderOpt, "sfNFTokenID"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnID(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnID"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnLgrSeq(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = domainIDValue; + + auto const fromSleOpt = entryFromSle.getDomainID(); + auto const fromBuilderOpt = entryFromBuilder.getDomainID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDomainID"); + expectEqualField(expected, *fromBuilderOpt, "sfDomainID"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(DirectoryNodeTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DirectoryNode{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(DirectoryNodeTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(DirectoryNodeBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(DirectoryNodeTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const indexesValue = canonical_VECTOR256(); + auto const rootIndexValue = canonical_UINT256(); + + DirectoryNodeBuilder builder{ + indexesValue, + rootIndexValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasOwner()); + EXPECT_FALSE(entry.getOwner().has_value()); + EXPECT_FALSE(entry.hasTakerPaysCurrency()); + EXPECT_FALSE(entry.getTakerPaysCurrency().has_value()); + EXPECT_FALSE(entry.hasTakerPaysIssuer()); + EXPECT_FALSE(entry.getTakerPaysIssuer().has_value()); + EXPECT_FALSE(entry.hasTakerGetsCurrency()); + EXPECT_FALSE(entry.getTakerGetsCurrency().has_value()); + EXPECT_FALSE(entry.hasTakerGetsIssuer()); + EXPECT_FALSE(entry.getTakerGetsIssuer().has_value()); + EXPECT_FALSE(entry.hasExchangeRate()); + EXPECT_FALSE(entry.getExchangeRate().has_value()); + EXPECT_FALSE(entry.hasIndexNext()); + EXPECT_FALSE(entry.getIndexNext().has_value()); + EXPECT_FALSE(entry.hasIndexPrevious()); + EXPECT_FALSE(entry.getIndexPrevious().has_value()); + EXPECT_FALSE(entry.hasNFTokenID()); + EXPECT_FALSE(entry.getNFTokenID().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnID()); + EXPECT_FALSE(entry.getPreviousTxnID().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnLgrSeq()); + EXPECT_FALSE(entry.getPreviousTxnLgrSeq().has_value()); + EXPECT_FALSE(entry.hasDomainID()); + EXPECT_FALSE(entry.getDomainID().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/EscrowTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/EscrowTests.cpp new file mode 100644 index 0000000000..2dbb450e28 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/EscrowTests.cpp @@ -0,0 +1,491 @@ +// Auto-generated unit tests for ledger entry Escrow + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(EscrowTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const conditionValue = canonical_VL(); + auto const cancelAfterValue = canonical_UINT32(); + auto const finishAfterValue = canonical_UINT32(); + auto const sourceTagValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const destinationNodeValue = canonical_UINT64(); + auto const transferRateValue = canonical_UINT32(); + auto const issuerNodeValue = canonical_UINT64(); + + EscrowBuilder builder{ + accountValue, + destinationValue, + amountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setSequence(sequenceValue); + builder.setCondition(conditionValue); + builder.setCancelAfter(cancelAfterValue); + builder.setFinishAfter(finishAfterValue); + builder.setSourceTag(sourceTagValue); + builder.setDestinationTag(destinationTagValue); + builder.setDestinationNode(destinationNodeValue); + builder.setTransferRate(transferRateValue); + builder.setIssuerNode(issuerNodeValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = destinationValue; + auto const actual = entry.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = entry.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + auto const actualOpt = entry.getSequence(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfSequence"); + EXPECT_TRUE(entry.hasSequence()); + } + + { + auto const& expected = conditionValue; + auto const actualOpt = entry.getCondition(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCondition"); + EXPECT_TRUE(entry.hasCondition()); + } + + { + auto const& expected = cancelAfterValue; + auto const actualOpt = entry.getCancelAfter(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCancelAfter"); + EXPECT_TRUE(entry.hasCancelAfter()); + } + + { + auto const& expected = finishAfterValue; + auto const actualOpt = entry.getFinishAfter(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfFinishAfter"); + EXPECT_TRUE(entry.hasFinishAfter()); + } + + { + auto const& expected = sourceTagValue; + auto const actualOpt = entry.getSourceTag(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfSourceTag"); + EXPECT_TRUE(entry.hasSourceTag()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = entry.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(entry.hasDestinationTag()); + } + + { + auto const& expected = destinationNodeValue; + auto const actualOpt = entry.getDestinationNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDestinationNode"); + EXPECT_TRUE(entry.hasDestinationNode()); + } + + { + auto const& expected = transferRateValue; + auto const actualOpt = entry.getTransferRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTransferRate"); + EXPECT_TRUE(entry.hasTransferRate()); + } + + { + auto const& expected = issuerNodeValue; + auto const actualOpt = entry.getIssuerNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfIssuerNode"); + EXPECT_TRUE(entry.hasIssuerNode()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(EscrowTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const conditionValue = canonical_VL(); + auto const cancelAfterValue = canonical_UINT32(); + auto const finishAfterValue = canonical_UINT32(); + auto const sourceTagValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const destinationNodeValue = canonical_UINT64(); + auto const transferRateValue = canonical_UINT32(); + auto const issuerNodeValue = canonical_UINT64(); + + auto sle = std::make_shared(Escrow::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfDestination) = destinationValue; + sle->at(sfAmount) = amountValue; + sle->at(sfCondition) = conditionValue; + sle->at(sfCancelAfter) = cancelAfterValue; + sle->at(sfFinishAfter) = finishAfterValue; + sle->at(sfSourceTag) = sourceTagValue; + sle->at(sfDestinationTag) = destinationTagValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfDestinationNode) = destinationNodeValue; + sle->at(sfTransferRate) = transferRateValue; + sle->at(sfIssuerNode) = issuerNodeValue; + + EscrowBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Escrow entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = destinationValue; + + auto const fromSle = entryFromSle.getDestination(); + auto const fromBuilder = entryFromBuilder.getDestination(); + + expectEqualField(expected, fromSle, "sfDestination"); + expectEqualField(expected, fromBuilder, "sfDestination"); + } + + { + auto const& expected = amountValue; + + auto const fromSle = entryFromSle.getAmount(); + auto const fromBuilder = entryFromBuilder.getAmount(); + + expectEqualField(expected, fromSle, "sfAmount"); + expectEqualField(expected, fromBuilder, "sfAmount"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSleOpt = entryFromSle.getSequence(); + auto const fromBuilderOpt = entryFromBuilder.getSequence(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfSequence"); + expectEqualField(expected, *fromBuilderOpt, "sfSequence"); + } + + { + auto const& expected = conditionValue; + + auto const fromSleOpt = entryFromSle.getCondition(); + auto const fromBuilderOpt = entryFromBuilder.getCondition(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCondition"); + expectEqualField(expected, *fromBuilderOpt, "sfCondition"); + } + + { + auto const& expected = cancelAfterValue; + + auto const fromSleOpt = entryFromSle.getCancelAfter(); + auto const fromBuilderOpt = entryFromBuilder.getCancelAfter(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCancelAfter"); + expectEqualField(expected, *fromBuilderOpt, "sfCancelAfter"); + } + + { + auto const& expected = finishAfterValue; + + auto const fromSleOpt = entryFromSle.getFinishAfter(); + auto const fromBuilderOpt = entryFromBuilder.getFinishAfter(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfFinishAfter"); + expectEqualField(expected, *fromBuilderOpt, "sfFinishAfter"); + } + + { + auto const& expected = sourceTagValue; + + auto const fromSleOpt = entryFromSle.getSourceTag(); + auto const fromBuilderOpt = entryFromBuilder.getSourceTag(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfSourceTag"); + expectEqualField(expected, *fromBuilderOpt, "sfSourceTag"); + } + + { + auto const& expected = destinationTagValue; + + auto const fromSleOpt = entryFromSle.getDestinationTag(); + auto const fromBuilderOpt = entryFromBuilder.getDestinationTag(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDestinationTag"); + expectEqualField(expected, *fromBuilderOpt, "sfDestinationTag"); + } + + { + auto const& expected = destinationNodeValue; + + auto const fromSleOpt = entryFromSle.getDestinationNode(); + auto const fromBuilderOpt = entryFromBuilder.getDestinationNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDestinationNode"); + expectEqualField(expected, *fromBuilderOpt, "sfDestinationNode"); + } + + { + auto const& expected = transferRateValue; + + auto const fromSleOpt = entryFromSle.getTransferRate(); + auto const fromBuilderOpt = entryFromBuilder.getTransferRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTransferRate"); + expectEqualField(expected, *fromBuilderOpt, "sfTransferRate"); + } + + { + auto const& expected = issuerNodeValue; + + auto const fromSleOpt = entryFromSle.getIssuerNode(); + auto const fromBuilderOpt = entryFromBuilder.getIssuerNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfIssuerNode"); + expectEqualField(expected, *fromBuilderOpt, "sfIssuerNode"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(EscrowTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Escrow{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(EscrowTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(EscrowBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(EscrowTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + EscrowBuilder builder{ + accountValue, + destinationValue, + amountValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasSequence()); + EXPECT_FALSE(entry.getSequence().has_value()); + EXPECT_FALSE(entry.hasCondition()); + EXPECT_FALSE(entry.getCondition().has_value()); + EXPECT_FALSE(entry.hasCancelAfter()); + EXPECT_FALSE(entry.getCancelAfter().has_value()); + EXPECT_FALSE(entry.hasFinishAfter()); + EXPECT_FALSE(entry.getFinishAfter().has_value()); + EXPECT_FALSE(entry.hasSourceTag()); + EXPECT_FALSE(entry.getSourceTag().has_value()); + EXPECT_FALSE(entry.hasDestinationTag()); + EXPECT_FALSE(entry.getDestinationTag().has_value()); + EXPECT_FALSE(entry.hasDestinationNode()); + EXPECT_FALSE(entry.getDestinationNode().has_value()); + EXPECT_FALSE(entry.hasTransferRate()); + EXPECT_FALSE(entry.getTransferRate().has_value()); + EXPECT_FALSE(entry.hasIssuerNode()); + EXPECT_FALSE(entry.getIssuerNode().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/FeeSettingsTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/FeeSettingsTests.cpp new file mode 100644 index 0000000000..479d0c56c6 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/FeeSettingsTests.cpp @@ -0,0 +1,359 @@ +// Auto-generated unit tests for ledger entry FeeSettings + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(FeeSettingsTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const baseFeeValue = canonical_UINT64(); + auto const referenceFeeUnitsValue = canonical_UINT32(); + auto const reserveBaseValue = canonical_UINT32(); + auto const reserveIncrementValue = canonical_UINT32(); + auto const baseFeeDropsValue = canonical_AMOUNT(); + auto const reserveBaseDropsValue = canonical_AMOUNT(); + auto const reserveIncrementDropsValue = canonical_AMOUNT(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + FeeSettingsBuilder builder{ + }; + + builder.setBaseFee(baseFeeValue); + builder.setReferenceFeeUnits(referenceFeeUnitsValue); + builder.setReserveBase(reserveBaseValue); + builder.setReserveIncrement(reserveIncrementValue); + builder.setBaseFeeDrops(baseFeeDropsValue); + builder.setReserveBaseDrops(reserveBaseDropsValue); + builder.setReserveIncrementDrops(reserveIncrementDropsValue); + builder.setPreviousTxnID(previousTxnIDValue); + builder.setPreviousTxnLgrSeq(previousTxnLgrSeqValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = baseFeeValue; + auto const actualOpt = entry.getBaseFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfBaseFee"); + EXPECT_TRUE(entry.hasBaseFee()); + } + + { + auto const& expected = referenceFeeUnitsValue; + auto const actualOpt = entry.getReferenceFeeUnits(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfReferenceFeeUnits"); + EXPECT_TRUE(entry.hasReferenceFeeUnits()); + } + + { + auto const& expected = reserveBaseValue; + auto const actualOpt = entry.getReserveBase(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfReserveBase"); + EXPECT_TRUE(entry.hasReserveBase()); + } + + { + auto const& expected = reserveIncrementValue; + auto const actualOpt = entry.getReserveIncrement(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfReserveIncrement"); + EXPECT_TRUE(entry.hasReserveIncrement()); + } + + { + auto const& expected = baseFeeDropsValue; + auto const actualOpt = entry.getBaseFeeDrops(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfBaseFeeDrops"); + EXPECT_TRUE(entry.hasBaseFeeDrops()); + } + + { + auto const& expected = reserveBaseDropsValue; + auto const actualOpt = entry.getReserveBaseDrops(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfReserveBaseDrops"); + EXPECT_TRUE(entry.hasReserveBaseDrops()); + } + + { + auto const& expected = reserveIncrementDropsValue; + auto const actualOpt = entry.getReserveIncrementDrops(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfReserveIncrementDrops"); + EXPECT_TRUE(entry.hasReserveIncrementDrops()); + } + + { + auto const& expected = previousTxnIDValue; + auto const actualOpt = entry.getPreviousTxnID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnID"); + EXPECT_TRUE(entry.hasPreviousTxnID()); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actualOpt = entry.getPreviousTxnLgrSeq(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnLgrSeq"); + EXPECT_TRUE(entry.hasPreviousTxnLgrSeq()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(FeeSettingsTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const baseFeeValue = canonical_UINT64(); + auto const referenceFeeUnitsValue = canonical_UINT32(); + auto const reserveBaseValue = canonical_UINT32(); + auto const reserveIncrementValue = canonical_UINT32(); + auto const baseFeeDropsValue = canonical_AMOUNT(); + auto const reserveBaseDropsValue = canonical_AMOUNT(); + auto const reserveIncrementDropsValue = canonical_AMOUNT(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(FeeSettings::entryType, index); + + sle->at(sfBaseFee) = baseFeeValue; + sle->at(sfReferenceFeeUnits) = referenceFeeUnitsValue; + sle->at(sfReserveBase) = reserveBaseValue; + sle->at(sfReserveIncrement) = reserveIncrementValue; + sle->at(sfBaseFeeDrops) = baseFeeDropsValue; + sle->at(sfReserveBaseDrops) = reserveBaseDropsValue; + sle->at(sfReserveIncrementDrops) = reserveIncrementDropsValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + FeeSettingsBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + FeeSettings entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = baseFeeValue; + + auto const fromSleOpt = entryFromSle.getBaseFee(); + auto const fromBuilderOpt = entryFromBuilder.getBaseFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfBaseFee"); + expectEqualField(expected, *fromBuilderOpt, "sfBaseFee"); + } + + { + auto const& expected = referenceFeeUnitsValue; + + auto const fromSleOpt = entryFromSle.getReferenceFeeUnits(); + auto const fromBuilderOpt = entryFromBuilder.getReferenceFeeUnits(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfReferenceFeeUnits"); + expectEqualField(expected, *fromBuilderOpt, "sfReferenceFeeUnits"); + } + + { + auto const& expected = reserveBaseValue; + + auto const fromSleOpt = entryFromSle.getReserveBase(); + auto const fromBuilderOpt = entryFromBuilder.getReserveBase(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfReserveBase"); + expectEqualField(expected, *fromBuilderOpt, "sfReserveBase"); + } + + { + auto const& expected = reserveIncrementValue; + + auto const fromSleOpt = entryFromSle.getReserveIncrement(); + auto const fromBuilderOpt = entryFromBuilder.getReserveIncrement(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfReserveIncrement"); + expectEqualField(expected, *fromBuilderOpt, "sfReserveIncrement"); + } + + { + auto const& expected = baseFeeDropsValue; + + auto const fromSleOpt = entryFromSle.getBaseFeeDrops(); + auto const fromBuilderOpt = entryFromBuilder.getBaseFeeDrops(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfBaseFeeDrops"); + expectEqualField(expected, *fromBuilderOpt, "sfBaseFeeDrops"); + } + + { + auto const& expected = reserveBaseDropsValue; + + auto const fromSleOpt = entryFromSle.getReserveBaseDrops(); + auto const fromBuilderOpt = entryFromBuilder.getReserveBaseDrops(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfReserveBaseDrops"); + expectEqualField(expected, *fromBuilderOpt, "sfReserveBaseDrops"); + } + + { + auto const& expected = reserveIncrementDropsValue; + + auto const fromSleOpt = entryFromSle.getReserveIncrementDrops(); + auto const fromBuilderOpt = entryFromBuilder.getReserveIncrementDrops(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfReserveIncrementDrops"); + expectEqualField(expected, *fromBuilderOpt, "sfReserveIncrementDrops"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnID(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnID"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnLgrSeq(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(FeeSettingsTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(FeeSettings{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(FeeSettingsTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(FeeSettingsBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(FeeSettingsTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + + FeeSettingsBuilder builder{ + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasBaseFee()); + EXPECT_FALSE(entry.getBaseFee().has_value()); + EXPECT_FALSE(entry.hasReferenceFeeUnits()); + EXPECT_FALSE(entry.getReferenceFeeUnits().has_value()); + EXPECT_FALSE(entry.hasReserveBase()); + EXPECT_FALSE(entry.getReserveBase().has_value()); + EXPECT_FALSE(entry.hasReserveIncrement()); + EXPECT_FALSE(entry.getReserveIncrement().has_value()); + EXPECT_FALSE(entry.hasBaseFeeDrops()); + EXPECT_FALSE(entry.getBaseFeeDrops().has_value()); + EXPECT_FALSE(entry.hasReserveBaseDrops()); + EXPECT_FALSE(entry.getReserveBaseDrops().has_value()); + EXPECT_FALSE(entry.hasReserveIncrementDrops()); + EXPECT_FALSE(entry.getReserveIncrementDrops().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnID()); + EXPECT_FALSE(entry.getPreviousTxnID().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnLgrSeq()); + EXPECT_FALSE(entry.getPreviousTxnLgrSeq().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/LedgerHashesTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/LedgerHashesTests.cpp new file mode 100644 index 0000000000..8a7ae38749 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/LedgerHashesTests.cpp @@ -0,0 +1,192 @@ +// Auto-generated unit tests for ledger entry LedgerHashes + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(LedgerHashesTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const firstLedgerSequenceValue = canonical_UINT32(); + auto const lastLedgerSequenceValue = canonical_UINT32(); + auto const hashesValue = canonical_VECTOR256(); + + LedgerHashesBuilder builder{ + hashesValue + }; + + builder.setFirstLedgerSequence(firstLedgerSequenceValue); + builder.setLastLedgerSequence(lastLedgerSequenceValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = hashesValue; + auto const actual = entry.getHashes(); + expectEqualField(expected, actual, "sfHashes"); + } + + { + auto const& expected = firstLedgerSequenceValue; + auto const actualOpt = entry.getFirstLedgerSequence(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfFirstLedgerSequence"); + EXPECT_TRUE(entry.hasFirstLedgerSequence()); + } + + { + auto const& expected = lastLedgerSequenceValue; + auto const actualOpt = entry.getLastLedgerSequence(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLastLedgerSequence"); + EXPECT_TRUE(entry.hasLastLedgerSequence()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(LedgerHashesTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const firstLedgerSequenceValue = canonical_UINT32(); + auto const lastLedgerSequenceValue = canonical_UINT32(); + auto const hashesValue = canonical_VECTOR256(); + + auto sle = std::make_shared(LedgerHashes::entryType, index); + + sle->at(sfFirstLedgerSequence) = firstLedgerSequenceValue; + sle->at(sfLastLedgerSequence) = lastLedgerSequenceValue; + sle->at(sfHashes) = hashesValue; + + LedgerHashesBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + LedgerHashes entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = hashesValue; + + auto const fromSle = entryFromSle.getHashes(); + auto const fromBuilder = entryFromBuilder.getHashes(); + + expectEqualField(expected, fromSle, "sfHashes"); + expectEqualField(expected, fromBuilder, "sfHashes"); + } + + { + auto const& expected = firstLedgerSequenceValue; + + auto const fromSleOpt = entryFromSle.getFirstLedgerSequence(); + auto const fromBuilderOpt = entryFromBuilder.getFirstLedgerSequence(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfFirstLedgerSequence"); + expectEqualField(expected, *fromBuilderOpt, "sfFirstLedgerSequence"); + } + + { + auto const& expected = lastLedgerSequenceValue; + + auto const fromSleOpt = entryFromSle.getLastLedgerSequence(); + auto const fromBuilderOpt = entryFromBuilder.getLastLedgerSequence(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLastLedgerSequence"); + expectEqualField(expected, *fromBuilderOpt, "sfLastLedgerSequence"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(LedgerHashesTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(LedgerHashes{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(LedgerHashesTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(LedgerHashesBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(LedgerHashesTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const hashesValue = canonical_VECTOR256(); + + LedgerHashesBuilder builder{ + hashesValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasFirstLedgerSequence()); + EXPECT_FALSE(entry.getFirstLedgerSequence().has_value()); + EXPECT_FALSE(entry.hasLastLedgerSequence()); + EXPECT_FALSE(entry.getLastLedgerSequence().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanBrokerTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanBrokerTests.cpp new file mode 100644 index 0000000000..fba8c539d2 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanBrokerTests.cpp @@ -0,0 +1,530 @@ +// Auto-generated unit tests for ledger entry LoanBroker + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(LoanBrokerTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const vaultNodeValue = canonical_UINT64(); + auto const vaultIDValue = canonical_UINT256(); + auto const accountValue = canonical_ACCOUNT(); + auto const ownerValue = canonical_ACCOUNT(); + auto const loanSequenceValue = canonical_UINT32(); + auto const dataValue = canonical_VL(); + auto const managementFeeRateValue = canonical_UINT16(); + auto const ownerCountValue = canonical_UINT32(); + auto const debtTotalValue = canonical_NUMBER(); + auto const debtMaximumValue = canonical_NUMBER(); + auto const coverAvailableValue = canonical_NUMBER(); + auto const coverRateMinimumValue = canonical_UINT32(); + auto const coverRateLiquidationValue = canonical_UINT32(); + + LoanBrokerBuilder builder{ + previousTxnIDValue, + previousTxnLgrSeqValue, + sequenceValue, + ownerNodeValue, + vaultNodeValue, + vaultIDValue, + accountValue, + ownerValue, + loanSequenceValue + }; + + builder.setData(dataValue); + builder.setManagementFeeRate(managementFeeRateValue); + builder.setOwnerCount(ownerCountValue); + builder.setDebtTotal(debtTotalValue); + builder.setDebtMaximum(debtMaximumValue); + builder.setCoverAvailable(coverAvailableValue); + builder.setCoverRateMinimum(coverRateMinimumValue); + builder.setCoverRateLiquidation(coverRateLiquidationValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = vaultNodeValue; + auto const actual = entry.getVaultNode(); + expectEqualField(expected, actual, "sfVaultNode"); + } + + { + auto const& expected = vaultIDValue; + auto const actual = entry.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = ownerValue; + auto const actual = entry.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = loanSequenceValue; + auto const actual = entry.getLoanSequence(); + expectEqualField(expected, actual, "sfLoanSequence"); + } + + { + auto const& expected = dataValue; + auto const actualOpt = entry.getData(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(entry.hasData()); + } + + { + auto const& expected = managementFeeRateValue; + auto const actualOpt = entry.getManagementFeeRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfManagementFeeRate"); + EXPECT_TRUE(entry.hasManagementFeeRate()); + } + + { + auto const& expected = ownerCountValue; + auto const actualOpt = entry.getOwnerCount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOwnerCount"); + EXPECT_TRUE(entry.hasOwnerCount()); + } + + { + auto const& expected = debtTotalValue; + auto const actualOpt = entry.getDebtTotal(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDebtTotal"); + EXPECT_TRUE(entry.hasDebtTotal()); + } + + { + auto const& expected = debtMaximumValue; + auto const actualOpt = entry.getDebtMaximum(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDebtMaximum"); + EXPECT_TRUE(entry.hasDebtMaximum()); + } + + { + auto const& expected = coverAvailableValue; + auto const actualOpt = entry.getCoverAvailable(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCoverAvailable"); + EXPECT_TRUE(entry.hasCoverAvailable()); + } + + { + auto const& expected = coverRateMinimumValue; + auto const actualOpt = entry.getCoverRateMinimum(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCoverRateMinimum"); + EXPECT_TRUE(entry.hasCoverRateMinimum()); + } + + { + auto const& expected = coverRateLiquidationValue; + auto const actualOpt = entry.getCoverRateLiquidation(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCoverRateLiquidation"); + EXPECT_TRUE(entry.hasCoverRateLiquidation()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(LoanBrokerTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const vaultNodeValue = canonical_UINT64(); + auto const vaultIDValue = canonical_UINT256(); + auto const accountValue = canonical_ACCOUNT(); + auto const ownerValue = canonical_ACCOUNT(); + auto const loanSequenceValue = canonical_UINT32(); + auto const dataValue = canonical_VL(); + auto const managementFeeRateValue = canonical_UINT16(); + auto const ownerCountValue = canonical_UINT32(); + auto const debtTotalValue = canonical_NUMBER(); + auto const debtMaximumValue = canonical_NUMBER(); + auto const coverAvailableValue = canonical_NUMBER(); + auto const coverRateMinimumValue = canonical_UINT32(); + auto const coverRateLiquidationValue = canonical_UINT32(); + + auto sle = std::make_shared(LoanBroker::entryType, index); + + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfVaultNode) = vaultNodeValue; + sle->at(sfVaultID) = vaultIDValue; + sle->at(sfAccount) = accountValue; + sle->at(sfOwner) = ownerValue; + sle->at(sfLoanSequence) = loanSequenceValue; + sle->at(sfData) = dataValue; + sle->at(sfManagementFeeRate) = managementFeeRateValue; + sle->at(sfOwnerCount) = ownerCountValue; + sle->at(sfDebtTotal) = debtTotalValue; + sle->at(sfDebtMaximum) = debtMaximumValue; + sle->at(sfCoverAvailable) = coverAvailableValue; + sle->at(sfCoverRateMinimum) = coverRateMinimumValue; + sle->at(sfCoverRateLiquidation) = coverRateLiquidationValue; + + LoanBrokerBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + LoanBroker entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = vaultNodeValue; + + auto const fromSle = entryFromSle.getVaultNode(); + auto const fromBuilder = entryFromBuilder.getVaultNode(); + + expectEqualField(expected, fromSle, "sfVaultNode"); + expectEqualField(expected, fromBuilder, "sfVaultNode"); + } + + { + auto const& expected = vaultIDValue; + + auto const fromSle = entryFromSle.getVaultID(); + auto const fromBuilder = entryFromBuilder.getVaultID(); + + expectEqualField(expected, fromSle, "sfVaultID"); + expectEqualField(expected, fromBuilder, "sfVaultID"); + } + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = ownerValue; + + auto const fromSle = entryFromSle.getOwner(); + auto const fromBuilder = entryFromBuilder.getOwner(); + + expectEqualField(expected, fromSle, "sfOwner"); + expectEqualField(expected, fromBuilder, "sfOwner"); + } + + { + auto const& expected = loanSequenceValue; + + auto const fromSle = entryFromSle.getLoanSequence(); + auto const fromBuilder = entryFromBuilder.getLoanSequence(); + + expectEqualField(expected, fromSle, "sfLoanSequence"); + expectEqualField(expected, fromBuilder, "sfLoanSequence"); + } + + { + auto const& expected = dataValue; + + auto const fromSleOpt = entryFromSle.getData(); + auto const fromBuilderOpt = entryFromBuilder.getData(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfData"); + expectEqualField(expected, *fromBuilderOpt, "sfData"); + } + + { + auto const& expected = managementFeeRateValue; + + auto const fromSleOpt = entryFromSle.getManagementFeeRate(); + auto const fromBuilderOpt = entryFromBuilder.getManagementFeeRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfManagementFeeRate"); + expectEqualField(expected, *fromBuilderOpt, "sfManagementFeeRate"); + } + + { + auto const& expected = ownerCountValue; + + auto const fromSleOpt = entryFromSle.getOwnerCount(); + auto const fromBuilderOpt = entryFromBuilder.getOwnerCount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOwnerCount"); + expectEqualField(expected, *fromBuilderOpt, "sfOwnerCount"); + } + + { + auto const& expected = debtTotalValue; + + auto const fromSleOpt = entryFromSle.getDebtTotal(); + auto const fromBuilderOpt = entryFromBuilder.getDebtTotal(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDebtTotal"); + expectEqualField(expected, *fromBuilderOpt, "sfDebtTotal"); + } + + { + auto const& expected = debtMaximumValue; + + auto const fromSleOpt = entryFromSle.getDebtMaximum(); + auto const fromBuilderOpt = entryFromBuilder.getDebtMaximum(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDebtMaximum"); + expectEqualField(expected, *fromBuilderOpt, "sfDebtMaximum"); + } + + { + auto const& expected = coverAvailableValue; + + auto const fromSleOpt = entryFromSle.getCoverAvailable(); + auto const fromBuilderOpt = entryFromBuilder.getCoverAvailable(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCoverAvailable"); + expectEqualField(expected, *fromBuilderOpt, "sfCoverAvailable"); + } + + { + auto const& expected = coverRateMinimumValue; + + auto const fromSleOpt = entryFromSle.getCoverRateMinimum(); + auto const fromBuilderOpt = entryFromBuilder.getCoverRateMinimum(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCoverRateMinimum"); + expectEqualField(expected, *fromBuilderOpt, "sfCoverRateMinimum"); + } + + { + auto const& expected = coverRateLiquidationValue; + + auto const fromSleOpt = entryFromSle.getCoverRateLiquidation(); + auto const fromBuilderOpt = entryFromBuilder.getCoverRateLiquidation(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCoverRateLiquidation"); + expectEqualField(expected, *fromBuilderOpt, "sfCoverRateLiquidation"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(LoanBrokerTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(LoanBroker{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(LoanBrokerTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(LoanBrokerBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(LoanBrokerTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const vaultNodeValue = canonical_UINT64(); + auto const vaultIDValue = canonical_UINT256(); + auto const accountValue = canonical_ACCOUNT(); + auto const ownerValue = canonical_ACCOUNT(); + auto const loanSequenceValue = canonical_UINT32(); + + LoanBrokerBuilder builder{ + previousTxnIDValue, + previousTxnLgrSeqValue, + sequenceValue, + ownerNodeValue, + vaultNodeValue, + vaultIDValue, + accountValue, + ownerValue, + loanSequenceValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasData()); + EXPECT_FALSE(entry.getData().has_value()); + EXPECT_FALSE(entry.hasManagementFeeRate()); + EXPECT_FALSE(entry.getManagementFeeRate().has_value()); + EXPECT_FALSE(entry.hasOwnerCount()); + EXPECT_FALSE(entry.getOwnerCount().has_value()); + EXPECT_FALSE(entry.hasDebtTotal()); + EXPECT_FALSE(entry.getDebtTotal().has_value()); + EXPECT_FALSE(entry.hasDebtMaximum()); + EXPECT_FALSE(entry.getDebtMaximum().has_value()); + EXPECT_FALSE(entry.hasCoverAvailable()); + EXPECT_FALSE(entry.getCoverAvailable().has_value()); + EXPECT_FALSE(entry.hasCoverRateMinimum()); + EXPECT_FALSE(entry.getCoverRateMinimum().has_value()); + EXPECT_FALSE(entry.hasCoverRateLiquidation()); + EXPECT_FALSE(entry.getCoverRateLiquidation().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp new file mode 100644 index 0000000000..845a8337b9 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp @@ -0,0 +1,795 @@ +// Auto-generated unit tests for ledger entry Loan + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(LoanTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const loanBrokerNodeValue = canonical_UINT64(); + auto const loanBrokerIDValue = canonical_UINT256(); + auto const loanSequenceValue = canonical_UINT32(); + auto const borrowerValue = canonical_ACCOUNT(); + auto const loanOriginationFeeValue = canonical_NUMBER(); + auto const loanServiceFeeValue = canonical_NUMBER(); + auto const latePaymentFeeValue = canonical_NUMBER(); + auto const closePaymentFeeValue = canonical_NUMBER(); + auto const overpaymentFeeValue = canonical_UINT32(); + auto const interestRateValue = canonical_UINT32(); + auto const lateInterestRateValue = canonical_UINT32(); + auto const closeInterestRateValue = canonical_UINT32(); + auto const overpaymentInterestRateValue = canonical_UINT32(); + auto const startDateValue = canonical_UINT32(); + auto const paymentIntervalValue = canonical_UINT32(); + auto const gracePeriodValue = canonical_UINT32(); + auto const previousPaymentDueDateValue = canonical_UINT32(); + auto const nextPaymentDueDateValue = canonical_UINT32(); + auto const paymentRemainingValue = canonical_UINT32(); + auto const periodicPaymentValue = canonical_NUMBER(); + auto const principalOutstandingValue = canonical_NUMBER(); + auto const totalValueOutstandingValue = canonical_NUMBER(); + auto const managementFeeOutstandingValue = canonical_NUMBER(); + auto const loanScaleValue = canonical_INT32(); + + LoanBuilder builder{ + previousTxnIDValue, + previousTxnLgrSeqValue, + ownerNodeValue, + loanBrokerNodeValue, + loanBrokerIDValue, + loanSequenceValue, + borrowerValue, + startDateValue, + paymentIntervalValue, + periodicPaymentValue + }; + + builder.setLoanOriginationFee(loanOriginationFeeValue); + builder.setLoanServiceFee(loanServiceFeeValue); + builder.setLatePaymentFee(latePaymentFeeValue); + builder.setClosePaymentFee(closePaymentFeeValue); + builder.setOverpaymentFee(overpaymentFeeValue); + builder.setInterestRate(interestRateValue); + builder.setLateInterestRate(lateInterestRateValue); + builder.setCloseInterestRate(closeInterestRateValue); + builder.setOverpaymentInterestRate(overpaymentInterestRateValue); + builder.setGracePeriod(gracePeriodValue); + builder.setPreviousPaymentDueDate(previousPaymentDueDateValue); + builder.setNextPaymentDueDate(nextPaymentDueDateValue); + builder.setPaymentRemaining(paymentRemainingValue); + builder.setPrincipalOutstanding(principalOutstandingValue); + builder.setTotalValueOutstanding(totalValueOutstandingValue); + builder.setManagementFeeOutstanding(managementFeeOutstandingValue); + builder.setLoanScale(loanScaleValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = loanBrokerNodeValue; + auto const actual = entry.getLoanBrokerNode(); + expectEqualField(expected, actual, "sfLoanBrokerNode"); + } + + { + auto const& expected = loanBrokerIDValue; + auto const actual = entry.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = loanSequenceValue; + auto const actual = entry.getLoanSequence(); + expectEqualField(expected, actual, "sfLoanSequence"); + } + + { + auto const& expected = borrowerValue; + auto const actual = entry.getBorrower(); + expectEqualField(expected, actual, "sfBorrower"); + } + + { + auto const& expected = startDateValue; + auto const actual = entry.getStartDate(); + expectEqualField(expected, actual, "sfStartDate"); + } + + { + auto const& expected = paymentIntervalValue; + auto const actual = entry.getPaymentInterval(); + expectEqualField(expected, actual, "sfPaymentInterval"); + } + + { + auto const& expected = periodicPaymentValue; + auto const actual = entry.getPeriodicPayment(); + expectEqualField(expected, actual, "sfPeriodicPayment"); + } + + { + auto const& expected = loanOriginationFeeValue; + auto const actualOpt = entry.getLoanOriginationFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLoanOriginationFee"); + EXPECT_TRUE(entry.hasLoanOriginationFee()); + } + + { + auto const& expected = loanServiceFeeValue; + auto const actualOpt = entry.getLoanServiceFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLoanServiceFee"); + EXPECT_TRUE(entry.hasLoanServiceFee()); + } + + { + auto const& expected = latePaymentFeeValue; + auto const actualOpt = entry.getLatePaymentFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLatePaymentFee"); + EXPECT_TRUE(entry.hasLatePaymentFee()); + } + + { + auto const& expected = closePaymentFeeValue; + auto const actualOpt = entry.getClosePaymentFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfClosePaymentFee"); + EXPECT_TRUE(entry.hasClosePaymentFee()); + } + + { + auto const& expected = overpaymentFeeValue; + auto const actualOpt = entry.getOverpaymentFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOverpaymentFee"); + EXPECT_TRUE(entry.hasOverpaymentFee()); + } + + { + auto const& expected = interestRateValue; + auto const actualOpt = entry.getInterestRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfInterestRate"); + EXPECT_TRUE(entry.hasInterestRate()); + } + + { + auto const& expected = lateInterestRateValue; + auto const actualOpt = entry.getLateInterestRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLateInterestRate"); + EXPECT_TRUE(entry.hasLateInterestRate()); + } + + { + auto const& expected = closeInterestRateValue; + auto const actualOpt = entry.getCloseInterestRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCloseInterestRate"); + EXPECT_TRUE(entry.hasCloseInterestRate()); + } + + { + auto const& expected = overpaymentInterestRateValue; + auto const actualOpt = entry.getOverpaymentInterestRate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOverpaymentInterestRate"); + EXPECT_TRUE(entry.hasOverpaymentInterestRate()); + } + + { + auto const& expected = gracePeriodValue; + auto const actualOpt = entry.getGracePeriod(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfGracePeriod"); + EXPECT_TRUE(entry.hasGracePeriod()); + } + + { + auto const& expected = previousPaymentDueDateValue; + auto const actualOpt = entry.getPreviousPaymentDueDate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousPaymentDueDate"); + EXPECT_TRUE(entry.hasPreviousPaymentDueDate()); + } + + { + auto const& expected = nextPaymentDueDateValue; + auto const actualOpt = entry.getNextPaymentDueDate(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfNextPaymentDueDate"); + EXPECT_TRUE(entry.hasNextPaymentDueDate()); + } + + { + auto const& expected = paymentRemainingValue; + auto const actualOpt = entry.getPaymentRemaining(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPaymentRemaining"); + EXPECT_TRUE(entry.hasPaymentRemaining()); + } + + { + auto const& expected = principalOutstandingValue; + auto const actualOpt = entry.getPrincipalOutstanding(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPrincipalOutstanding"); + EXPECT_TRUE(entry.hasPrincipalOutstanding()); + } + + { + auto const& expected = totalValueOutstandingValue; + auto const actualOpt = entry.getTotalValueOutstanding(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTotalValueOutstanding"); + EXPECT_TRUE(entry.hasTotalValueOutstanding()); + } + + { + auto const& expected = managementFeeOutstandingValue; + auto const actualOpt = entry.getManagementFeeOutstanding(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfManagementFeeOutstanding"); + EXPECT_TRUE(entry.hasManagementFeeOutstanding()); + } + + { + auto const& expected = loanScaleValue; + auto const actualOpt = entry.getLoanScale(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLoanScale"); + EXPECT_TRUE(entry.hasLoanScale()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(LoanTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const loanBrokerNodeValue = canonical_UINT64(); + auto const loanBrokerIDValue = canonical_UINT256(); + auto const loanSequenceValue = canonical_UINT32(); + auto const borrowerValue = canonical_ACCOUNT(); + auto const loanOriginationFeeValue = canonical_NUMBER(); + auto const loanServiceFeeValue = canonical_NUMBER(); + auto const latePaymentFeeValue = canonical_NUMBER(); + auto const closePaymentFeeValue = canonical_NUMBER(); + auto const overpaymentFeeValue = canonical_UINT32(); + auto const interestRateValue = canonical_UINT32(); + auto const lateInterestRateValue = canonical_UINT32(); + auto const closeInterestRateValue = canonical_UINT32(); + auto const overpaymentInterestRateValue = canonical_UINT32(); + auto const startDateValue = canonical_UINT32(); + auto const paymentIntervalValue = canonical_UINT32(); + auto const gracePeriodValue = canonical_UINT32(); + auto const previousPaymentDueDateValue = canonical_UINT32(); + auto const nextPaymentDueDateValue = canonical_UINT32(); + auto const paymentRemainingValue = canonical_UINT32(); + auto const periodicPaymentValue = canonical_NUMBER(); + auto const principalOutstandingValue = canonical_NUMBER(); + auto const totalValueOutstandingValue = canonical_NUMBER(); + auto const managementFeeOutstandingValue = canonical_NUMBER(); + auto const loanScaleValue = canonical_INT32(); + + auto sle = std::make_shared(Loan::entryType, index); + + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfLoanBrokerNode) = loanBrokerNodeValue; + sle->at(sfLoanBrokerID) = loanBrokerIDValue; + sle->at(sfLoanSequence) = loanSequenceValue; + sle->at(sfBorrower) = borrowerValue; + sle->at(sfLoanOriginationFee) = loanOriginationFeeValue; + sle->at(sfLoanServiceFee) = loanServiceFeeValue; + sle->at(sfLatePaymentFee) = latePaymentFeeValue; + sle->at(sfClosePaymentFee) = closePaymentFeeValue; + sle->at(sfOverpaymentFee) = overpaymentFeeValue; + sle->at(sfInterestRate) = interestRateValue; + sle->at(sfLateInterestRate) = lateInterestRateValue; + sle->at(sfCloseInterestRate) = closeInterestRateValue; + sle->at(sfOverpaymentInterestRate) = overpaymentInterestRateValue; + sle->at(sfStartDate) = startDateValue; + sle->at(sfPaymentInterval) = paymentIntervalValue; + sle->at(sfGracePeriod) = gracePeriodValue; + sle->at(sfPreviousPaymentDueDate) = previousPaymentDueDateValue; + sle->at(sfNextPaymentDueDate) = nextPaymentDueDateValue; + sle->at(sfPaymentRemaining) = paymentRemainingValue; + sle->at(sfPeriodicPayment) = periodicPaymentValue; + sle->at(sfPrincipalOutstanding) = principalOutstandingValue; + sle->at(sfTotalValueOutstanding) = totalValueOutstandingValue; + sle->at(sfManagementFeeOutstanding) = managementFeeOutstandingValue; + sle->at(sfLoanScale) = loanScaleValue; + + LoanBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Loan entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = loanBrokerNodeValue; + + auto const fromSle = entryFromSle.getLoanBrokerNode(); + auto const fromBuilder = entryFromBuilder.getLoanBrokerNode(); + + expectEqualField(expected, fromSle, "sfLoanBrokerNode"); + expectEqualField(expected, fromBuilder, "sfLoanBrokerNode"); + } + + { + auto const& expected = loanBrokerIDValue; + + auto const fromSle = entryFromSle.getLoanBrokerID(); + auto const fromBuilder = entryFromBuilder.getLoanBrokerID(); + + expectEqualField(expected, fromSle, "sfLoanBrokerID"); + expectEqualField(expected, fromBuilder, "sfLoanBrokerID"); + } + + { + auto const& expected = loanSequenceValue; + + auto const fromSle = entryFromSle.getLoanSequence(); + auto const fromBuilder = entryFromBuilder.getLoanSequence(); + + expectEqualField(expected, fromSle, "sfLoanSequence"); + expectEqualField(expected, fromBuilder, "sfLoanSequence"); + } + + { + auto const& expected = borrowerValue; + + auto const fromSle = entryFromSle.getBorrower(); + auto const fromBuilder = entryFromBuilder.getBorrower(); + + expectEqualField(expected, fromSle, "sfBorrower"); + expectEqualField(expected, fromBuilder, "sfBorrower"); + } + + { + auto const& expected = startDateValue; + + auto const fromSle = entryFromSle.getStartDate(); + auto const fromBuilder = entryFromBuilder.getStartDate(); + + expectEqualField(expected, fromSle, "sfStartDate"); + expectEqualField(expected, fromBuilder, "sfStartDate"); + } + + { + auto const& expected = paymentIntervalValue; + + auto const fromSle = entryFromSle.getPaymentInterval(); + auto const fromBuilder = entryFromBuilder.getPaymentInterval(); + + expectEqualField(expected, fromSle, "sfPaymentInterval"); + expectEqualField(expected, fromBuilder, "sfPaymentInterval"); + } + + { + auto const& expected = periodicPaymentValue; + + auto const fromSle = entryFromSle.getPeriodicPayment(); + auto const fromBuilder = entryFromBuilder.getPeriodicPayment(); + + expectEqualField(expected, fromSle, "sfPeriodicPayment"); + expectEqualField(expected, fromBuilder, "sfPeriodicPayment"); + } + + { + auto const& expected = loanOriginationFeeValue; + + auto const fromSleOpt = entryFromSle.getLoanOriginationFee(); + auto const fromBuilderOpt = entryFromBuilder.getLoanOriginationFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLoanOriginationFee"); + expectEqualField(expected, *fromBuilderOpt, "sfLoanOriginationFee"); + } + + { + auto const& expected = loanServiceFeeValue; + + auto const fromSleOpt = entryFromSle.getLoanServiceFee(); + auto const fromBuilderOpt = entryFromBuilder.getLoanServiceFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLoanServiceFee"); + expectEqualField(expected, *fromBuilderOpt, "sfLoanServiceFee"); + } + + { + auto const& expected = latePaymentFeeValue; + + auto const fromSleOpt = entryFromSle.getLatePaymentFee(); + auto const fromBuilderOpt = entryFromBuilder.getLatePaymentFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLatePaymentFee"); + expectEqualField(expected, *fromBuilderOpt, "sfLatePaymentFee"); + } + + { + auto const& expected = closePaymentFeeValue; + + auto const fromSleOpt = entryFromSle.getClosePaymentFee(); + auto const fromBuilderOpt = entryFromBuilder.getClosePaymentFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfClosePaymentFee"); + expectEqualField(expected, *fromBuilderOpt, "sfClosePaymentFee"); + } + + { + auto const& expected = overpaymentFeeValue; + + auto const fromSleOpt = entryFromSle.getOverpaymentFee(); + auto const fromBuilderOpt = entryFromBuilder.getOverpaymentFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOverpaymentFee"); + expectEqualField(expected, *fromBuilderOpt, "sfOverpaymentFee"); + } + + { + auto const& expected = interestRateValue; + + auto const fromSleOpt = entryFromSle.getInterestRate(); + auto const fromBuilderOpt = entryFromBuilder.getInterestRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfInterestRate"); + expectEqualField(expected, *fromBuilderOpt, "sfInterestRate"); + } + + { + auto const& expected = lateInterestRateValue; + + auto const fromSleOpt = entryFromSle.getLateInterestRate(); + auto const fromBuilderOpt = entryFromBuilder.getLateInterestRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLateInterestRate"); + expectEqualField(expected, *fromBuilderOpt, "sfLateInterestRate"); + } + + { + auto const& expected = closeInterestRateValue; + + auto const fromSleOpt = entryFromSle.getCloseInterestRate(); + auto const fromBuilderOpt = entryFromBuilder.getCloseInterestRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCloseInterestRate"); + expectEqualField(expected, *fromBuilderOpt, "sfCloseInterestRate"); + } + + { + auto const& expected = overpaymentInterestRateValue; + + auto const fromSleOpt = entryFromSle.getOverpaymentInterestRate(); + auto const fromBuilderOpt = entryFromBuilder.getOverpaymentInterestRate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOverpaymentInterestRate"); + expectEqualField(expected, *fromBuilderOpt, "sfOverpaymentInterestRate"); + } + + { + auto const& expected = gracePeriodValue; + + auto const fromSleOpt = entryFromSle.getGracePeriod(); + auto const fromBuilderOpt = entryFromBuilder.getGracePeriod(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfGracePeriod"); + expectEqualField(expected, *fromBuilderOpt, "sfGracePeriod"); + } + + { + auto const& expected = previousPaymentDueDateValue; + + auto const fromSleOpt = entryFromSle.getPreviousPaymentDueDate(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousPaymentDueDate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousPaymentDueDate"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousPaymentDueDate"); + } + + { + auto const& expected = nextPaymentDueDateValue; + + auto const fromSleOpt = entryFromSle.getNextPaymentDueDate(); + auto const fromBuilderOpt = entryFromBuilder.getNextPaymentDueDate(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfNextPaymentDueDate"); + expectEqualField(expected, *fromBuilderOpt, "sfNextPaymentDueDate"); + } + + { + auto const& expected = paymentRemainingValue; + + auto const fromSleOpt = entryFromSle.getPaymentRemaining(); + auto const fromBuilderOpt = entryFromBuilder.getPaymentRemaining(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPaymentRemaining"); + expectEqualField(expected, *fromBuilderOpt, "sfPaymentRemaining"); + } + + { + auto const& expected = principalOutstandingValue; + + auto const fromSleOpt = entryFromSle.getPrincipalOutstanding(); + auto const fromBuilderOpt = entryFromBuilder.getPrincipalOutstanding(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPrincipalOutstanding"); + expectEqualField(expected, *fromBuilderOpt, "sfPrincipalOutstanding"); + } + + { + auto const& expected = totalValueOutstandingValue; + + auto const fromSleOpt = entryFromSle.getTotalValueOutstanding(); + auto const fromBuilderOpt = entryFromBuilder.getTotalValueOutstanding(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTotalValueOutstanding"); + expectEqualField(expected, *fromBuilderOpt, "sfTotalValueOutstanding"); + } + + { + auto const& expected = managementFeeOutstandingValue; + + auto const fromSleOpt = entryFromSle.getManagementFeeOutstanding(); + auto const fromBuilderOpt = entryFromBuilder.getManagementFeeOutstanding(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfManagementFeeOutstanding"); + expectEqualField(expected, *fromBuilderOpt, "sfManagementFeeOutstanding"); + } + + { + auto const& expected = loanScaleValue; + + auto const fromSleOpt = entryFromSle.getLoanScale(); + auto const fromBuilderOpt = entryFromBuilder.getLoanScale(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLoanScale"); + expectEqualField(expected, *fromBuilderOpt, "sfLoanScale"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(LoanTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Loan{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(LoanTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(LoanBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(LoanTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const loanBrokerNodeValue = canonical_UINT64(); + auto const loanBrokerIDValue = canonical_UINT256(); + auto const loanSequenceValue = canonical_UINT32(); + auto const borrowerValue = canonical_ACCOUNT(); + auto const startDateValue = canonical_UINT32(); + auto const paymentIntervalValue = canonical_UINT32(); + auto const periodicPaymentValue = canonical_NUMBER(); + + LoanBuilder builder{ + previousTxnIDValue, + previousTxnLgrSeqValue, + ownerNodeValue, + loanBrokerNodeValue, + loanBrokerIDValue, + loanSequenceValue, + borrowerValue, + startDateValue, + paymentIntervalValue, + periodicPaymentValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasLoanOriginationFee()); + EXPECT_FALSE(entry.getLoanOriginationFee().has_value()); + EXPECT_FALSE(entry.hasLoanServiceFee()); + EXPECT_FALSE(entry.getLoanServiceFee().has_value()); + EXPECT_FALSE(entry.hasLatePaymentFee()); + EXPECT_FALSE(entry.getLatePaymentFee().has_value()); + EXPECT_FALSE(entry.hasClosePaymentFee()); + EXPECT_FALSE(entry.getClosePaymentFee().has_value()); + EXPECT_FALSE(entry.hasOverpaymentFee()); + EXPECT_FALSE(entry.getOverpaymentFee().has_value()); + EXPECT_FALSE(entry.hasInterestRate()); + EXPECT_FALSE(entry.getInterestRate().has_value()); + EXPECT_FALSE(entry.hasLateInterestRate()); + EXPECT_FALSE(entry.getLateInterestRate().has_value()); + EXPECT_FALSE(entry.hasCloseInterestRate()); + EXPECT_FALSE(entry.getCloseInterestRate().has_value()); + EXPECT_FALSE(entry.hasOverpaymentInterestRate()); + EXPECT_FALSE(entry.getOverpaymentInterestRate().has_value()); + EXPECT_FALSE(entry.hasGracePeriod()); + EXPECT_FALSE(entry.getGracePeriod().has_value()); + EXPECT_FALSE(entry.hasPreviousPaymentDueDate()); + EXPECT_FALSE(entry.getPreviousPaymentDueDate().has_value()); + EXPECT_FALSE(entry.hasNextPaymentDueDate()); + EXPECT_FALSE(entry.getNextPaymentDueDate().has_value()); + EXPECT_FALSE(entry.hasPaymentRemaining()); + EXPECT_FALSE(entry.getPaymentRemaining().has_value()); + EXPECT_FALSE(entry.hasPrincipalOutstanding()); + EXPECT_FALSE(entry.getPrincipalOutstanding().has_value()); + EXPECT_FALSE(entry.hasTotalValueOutstanding()); + EXPECT_FALSE(entry.getTotalValueOutstanding().has_value()); + EXPECT_FALSE(entry.hasManagementFeeOutstanding()); + EXPECT_FALSE(entry.getManagementFeeOutstanding().has_value()); + EXPECT_FALSE(entry.hasLoanScale()); + EXPECT_FALSE(entry.getLoanScale().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenIssuanceTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenIssuanceTests.cpp new file mode 100644 index 0000000000..e74af94a5f --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenIssuanceTests.cpp @@ -0,0 +1,437 @@ +// Auto-generated unit tests for ledger entry MPTokenIssuance + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(MPTokenIssuanceTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const issuerValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const transferFeeValue = canonical_UINT16(); + auto const ownerNodeValue = canonical_UINT64(); + auto const assetScaleValue = canonical_UINT8(); + auto const maximumAmountValue = canonical_UINT64(); + auto const outstandingAmountValue = canonical_UINT64(); + auto const lockedAmountValue = canonical_UINT64(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + auto const mutableFlagsValue = canonical_UINT32(); + + MPTokenIssuanceBuilder builder{ + issuerValue, + sequenceValue, + ownerNodeValue, + outstandingAmountValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setTransferFee(transferFeeValue); + builder.setAssetScale(assetScaleValue); + builder.setMaximumAmount(maximumAmountValue); + builder.setLockedAmount(lockedAmountValue); + builder.setMPTokenMetadata(mPTokenMetadataValue); + builder.setDomainID(domainIDValue); + builder.setMutableFlags(mutableFlagsValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = issuerValue; + auto const actual = entry.getIssuer(); + expectEqualField(expected, actual, "sfIssuer"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = outstandingAmountValue; + auto const actual = entry.getOutstandingAmount(); + expectEqualField(expected, actual, "sfOutstandingAmount"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = transferFeeValue; + auto const actualOpt = entry.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfTransferFee"); + EXPECT_TRUE(entry.hasTransferFee()); + } + + { + auto const& expected = assetScaleValue; + auto const actualOpt = entry.getAssetScale(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAssetScale"); + EXPECT_TRUE(entry.hasAssetScale()); + } + + { + auto const& expected = maximumAmountValue; + auto const actualOpt = entry.getMaximumAmount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMaximumAmount"); + EXPECT_TRUE(entry.hasMaximumAmount()); + } + + { + auto const& expected = lockedAmountValue; + auto const actualOpt = entry.getLockedAmount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLockedAmount"); + EXPECT_TRUE(entry.hasLockedAmount()); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = entry.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + EXPECT_TRUE(entry.hasMPTokenMetadata()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = entry.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(entry.hasDomainID()); + } + + { + auto const& expected = mutableFlagsValue; + auto const actualOpt = entry.getMutableFlags(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMutableFlags"); + EXPECT_TRUE(entry.hasMutableFlags()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(MPTokenIssuanceTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const issuerValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const transferFeeValue = canonical_UINT16(); + auto const ownerNodeValue = canonical_UINT64(); + auto const assetScaleValue = canonical_UINT8(); + auto const maximumAmountValue = canonical_UINT64(); + auto const outstandingAmountValue = canonical_UINT64(); + auto const lockedAmountValue = canonical_UINT64(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + auto const mutableFlagsValue = canonical_UINT32(); + + auto sle = std::make_shared(MPTokenIssuance::entryType, index); + + sle->at(sfIssuer) = issuerValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfTransferFee) = transferFeeValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfAssetScale) = assetScaleValue; + sle->at(sfMaximumAmount) = maximumAmountValue; + sle->at(sfOutstandingAmount) = outstandingAmountValue; + sle->at(sfLockedAmount) = lockedAmountValue; + sle->at(sfMPTokenMetadata) = mPTokenMetadataValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfDomainID) = domainIDValue; + sle->at(sfMutableFlags) = mutableFlagsValue; + + MPTokenIssuanceBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + MPTokenIssuance entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = issuerValue; + + auto const fromSle = entryFromSle.getIssuer(); + auto const fromBuilder = entryFromBuilder.getIssuer(); + + expectEqualField(expected, fromSle, "sfIssuer"); + expectEqualField(expected, fromBuilder, "sfIssuer"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = outstandingAmountValue; + + auto const fromSle = entryFromSle.getOutstandingAmount(); + auto const fromBuilder = entryFromBuilder.getOutstandingAmount(); + + expectEqualField(expected, fromSle, "sfOutstandingAmount"); + expectEqualField(expected, fromBuilder, "sfOutstandingAmount"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = transferFeeValue; + + auto const fromSleOpt = entryFromSle.getTransferFee(); + auto const fromBuilderOpt = entryFromBuilder.getTransferFee(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfTransferFee"); + expectEqualField(expected, *fromBuilderOpt, "sfTransferFee"); + } + + { + auto const& expected = assetScaleValue; + + auto const fromSleOpt = entryFromSle.getAssetScale(); + auto const fromBuilderOpt = entryFromBuilder.getAssetScale(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAssetScale"); + expectEqualField(expected, *fromBuilderOpt, "sfAssetScale"); + } + + { + auto const& expected = maximumAmountValue; + + auto const fromSleOpt = entryFromSle.getMaximumAmount(); + auto const fromBuilderOpt = entryFromBuilder.getMaximumAmount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMaximumAmount"); + expectEqualField(expected, *fromBuilderOpt, "sfMaximumAmount"); + } + + { + auto const& expected = lockedAmountValue; + + auto const fromSleOpt = entryFromSle.getLockedAmount(); + auto const fromBuilderOpt = entryFromBuilder.getLockedAmount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLockedAmount"); + expectEqualField(expected, *fromBuilderOpt, "sfLockedAmount"); + } + + { + auto const& expected = mPTokenMetadataValue; + + auto const fromSleOpt = entryFromSle.getMPTokenMetadata(); + auto const fromBuilderOpt = entryFromBuilder.getMPTokenMetadata(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMPTokenMetadata"); + expectEqualField(expected, *fromBuilderOpt, "sfMPTokenMetadata"); + } + + { + auto const& expected = domainIDValue; + + auto const fromSleOpt = entryFromSle.getDomainID(); + auto const fromBuilderOpt = entryFromBuilder.getDomainID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDomainID"); + expectEqualField(expected, *fromBuilderOpt, "sfDomainID"); + } + + { + auto const& expected = mutableFlagsValue; + + auto const fromSleOpt = entryFromSle.getMutableFlags(); + auto const fromBuilderOpt = entryFromBuilder.getMutableFlags(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMutableFlags"); + expectEqualField(expected, *fromBuilderOpt, "sfMutableFlags"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(MPTokenIssuanceTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(MPTokenIssuance{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(MPTokenIssuanceTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(MPTokenIssuanceBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(MPTokenIssuanceTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const issuerValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const outstandingAmountValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + MPTokenIssuanceBuilder builder{ + issuerValue, + sequenceValue, + ownerNodeValue, + outstandingAmountValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasTransferFee()); + EXPECT_FALSE(entry.getTransferFee().has_value()); + EXPECT_FALSE(entry.hasAssetScale()); + EXPECT_FALSE(entry.getAssetScale().has_value()); + EXPECT_FALSE(entry.hasMaximumAmount()); + EXPECT_FALSE(entry.getMaximumAmount().has_value()); + EXPECT_FALSE(entry.hasLockedAmount()); + EXPECT_FALSE(entry.getLockedAmount().has_value()); + EXPECT_FALSE(entry.hasMPTokenMetadata()); + EXPECT_FALSE(entry.getMPTokenMetadata().has_value()); + EXPECT_FALSE(entry.hasDomainID()); + EXPECT_FALSE(entry.getDomainID().has_value()); + EXPECT_FALSE(entry.hasMutableFlags()); + EXPECT_FALSE(entry.getMutableFlags().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenTests.cpp new file mode 100644 index 0000000000..c104e7b365 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/MPTokenTests.cpp @@ -0,0 +1,280 @@ +// Auto-generated unit tests for ledger entry MPToken + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(MPTokenTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const mPTAmountValue = canonical_UINT64(); + auto const lockedAmountValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + MPTokenBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setMPTAmount(mPTAmountValue); + builder.setLockedAmount(lockedAmountValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = entry.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = mPTAmountValue; + auto const actualOpt = entry.getMPTAmount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfMPTAmount"); + EXPECT_TRUE(entry.hasMPTAmount()); + } + + { + auto const& expected = lockedAmountValue; + auto const actualOpt = entry.getLockedAmount(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLockedAmount"); + EXPECT_TRUE(entry.hasLockedAmount()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(MPTokenTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const mPTAmountValue = canonical_UINT64(); + auto const lockedAmountValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(MPToken::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfMPTokenIssuanceID) = mPTokenIssuanceIDValue; + sle->at(sfMPTAmount) = mPTAmountValue; + sle->at(sfLockedAmount) = lockedAmountValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + MPTokenBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + MPToken entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = mPTokenIssuanceIDValue; + + auto const fromSle = entryFromSle.getMPTokenIssuanceID(); + auto const fromBuilder = entryFromBuilder.getMPTokenIssuanceID(); + + expectEqualField(expected, fromSle, "sfMPTokenIssuanceID"); + expectEqualField(expected, fromBuilder, "sfMPTokenIssuanceID"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = mPTAmountValue; + + auto const fromSleOpt = entryFromSle.getMPTAmount(); + auto const fromBuilderOpt = entryFromBuilder.getMPTAmount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfMPTAmount"); + expectEqualField(expected, *fromBuilderOpt, "sfMPTAmount"); + } + + { + auto const& expected = lockedAmountValue; + + auto const fromSleOpt = entryFromSle.getLockedAmount(); + auto const fromBuilderOpt = entryFromBuilder.getLockedAmount(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLockedAmount"); + expectEqualField(expected, *fromBuilderOpt, "sfLockedAmount"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(MPTokenTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(MPToken{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(MPTokenTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(MPTokenBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(MPTokenTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + MPTokenBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasMPTAmount()); + EXPECT_FALSE(entry.getMPTAmount().has_value()); + EXPECT_FALSE(entry.hasLockedAmount()); + EXPECT_FALSE(entry.getLockedAmount().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenOfferTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenOfferTests.cpp new file mode 100644 index 0000000000..9d039b2c38 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenOfferTests.cpp @@ -0,0 +1,324 @@ +// Auto-generated unit tests for ledger entry NFTokenOffer + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(NFTokenOfferTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const nFTokenIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const nFTokenOfferNodeValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const expirationValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + NFTokenOfferBuilder builder{ + ownerValue, + nFTokenIDValue, + amountValue, + ownerNodeValue, + nFTokenOfferNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setDestination(destinationValue); + builder.setExpiration(expirationValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = ownerValue; + auto const actual = entry.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = nFTokenIDValue; + auto const actual = entry.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + { + auto const& expected = amountValue; + auto const actual = entry.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = nFTokenOfferNodeValue; + auto const actual = entry.getNFTokenOfferNode(); + expectEqualField(expected, actual, "sfNFTokenOfferNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = destinationValue; + auto const actualOpt = entry.getDestination(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDestination"); + EXPECT_TRUE(entry.hasDestination()); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = entry.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(entry.hasExpiration()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(NFTokenOfferTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const nFTokenIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const nFTokenOfferNodeValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const expirationValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(NFTokenOffer::entryType, index); + + sle->at(sfOwner) = ownerValue; + sle->at(sfNFTokenID) = nFTokenIDValue; + sle->at(sfAmount) = amountValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfNFTokenOfferNode) = nFTokenOfferNodeValue; + sle->at(sfDestination) = destinationValue; + sle->at(sfExpiration) = expirationValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + NFTokenOfferBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + NFTokenOffer entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = ownerValue; + + auto const fromSle = entryFromSle.getOwner(); + auto const fromBuilder = entryFromBuilder.getOwner(); + + expectEqualField(expected, fromSle, "sfOwner"); + expectEqualField(expected, fromBuilder, "sfOwner"); + } + + { + auto const& expected = nFTokenIDValue; + + auto const fromSle = entryFromSle.getNFTokenID(); + auto const fromBuilder = entryFromBuilder.getNFTokenID(); + + expectEqualField(expected, fromSle, "sfNFTokenID"); + expectEqualField(expected, fromBuilder, "sfNFTokenID"); + } + + { + auto const& expected = amountValue; + + auto const fromSle = entryFromSle.getAmount(); + auto const fromBuilder = entryFromBuilder.getAmount(); + + expectEqualField(expected, fromSle, "sfAmount"); + expectEqualField(expected, fromBuilder, "sfAmount"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = nFTokenOfferNodeValue; + + auto const fromSle = entryFromSle.getNFTokenOfferNode(); + auto const fromBuilder = entryFromBuilder.getNFTokenOfferNode(); + + expectEqualField(expected, fromSle, "sfNFTokenOfferNode"); + expectEqualField(expected, fromBuilder, "sfNFTokenOfferNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = destinationValue; + + auto const fromSleOpt = entryFromSle.getDestination(); + auto const fromBuilderOpt = entryFromBuilder.getDestination(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDestination"); + expectEqualField(expected, *fromBuilderOpt, "sfDestination"); + } + + { + auto const& expected = expirationValue; + + auto const fromSleOpt = entryFromSle.getExpiration(); + auto const fromBuilderOpt = entryFromBuilder.getExpiration(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfExpiration"); + expectEqualField(expected, *fromBuilderOpt, "sfExpiration"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(NFTokenOfferTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(NFTokenOffer{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(NFTokenOfferTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(NFTokenOfferBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(NFTokenOfferTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const nFTokenIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const nFTokenOfferNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + NFTokenOfferBuilder builder{ + ownerValue, + nFTokenIDValue, + amountValue, + ownerNodeValue, + nFTokenOfferNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasDestination()); + EXPECT_FALSE(entry.getDestination().has_value()); + EXPECT_FALSE(entry.hasExpiration()); + EXPECT_FALSE(entry.getExpiration().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenPageTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenPageTests.cpp new file mode 100644 index 0000000000..5909050169 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/NFTokenPageTests.cpp @@ -0,0 +1,236 @@ +// Auto-generated unit tests for ledger entry NFTokenPage + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(NFTokenPageTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const previousPageMinValue = canonical_UINT256(); + auto const nextPageMinValue = canonical_UINT256(); + auto const nFTokensValue = canonical_ARRAY(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + NFTokenPageBuilder builder{ + nFTokensValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setPreviousPageMin(previousPageMinValue); + builder.setNextPageMin(nextPageMinValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = nFTokensValue; + auto const actual = entry.getNFTokens(); + expectEqualField(expected, actual, "sfNFTokens"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = previousPageMinValue; + auto const actualOpt = entry.getPreviousPageMin(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousPageMin"); + EXPECT_TRUE(entry.hasPreviousPageMin()); + } + + { + auto const& expected = nextPageMinValue; + auto const actualOpt = entry.getNextPageMin(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfNextPageMin"); + EXPECT_TRUE(entry.hasNextPageMin()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(NFTokenPageTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const previousPageMinValue = canonical_UINT256(); + auto const nextPageMinValue = canonical_UINT256(); + auto const nFTokensValue = canonical_ARRAY(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(NFTokenPage::entryType, index); + + sle->at(sfPreviousPageMin) = previousPageMinValue; + sle->at(sfNextPageMin) = nextPageMinValue; + sle->setFieldArray(sfNFTokens, nFTokensValue); + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + NFTokenPageBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + NFTokenPage entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = nFTokensValue; + + auto const fromSle = entryFromSle.getNFTokens(); + auto const fromBuilder = entryFromBuilder.getNFTokens(); + + expectEqualField(expected, fromSle, "sfNFTokens"); + expectEqualField(expected, fromBuilder, "sfNFTokens"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = previousPageMinValue; + + auto const fromSleOpt = entryFromSle.getPreviousPageMin(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousPageMin(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousPageMin"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousPageMin"); + } + + { + auto const& expected = nextPageMinValue; + + auto const fromSleOpt = entryFromSle.getNextPageMin(); + auto const fromBuilderOpt = entryFromBuilder.getNextPageMin(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfNextPageMin"); + expectEqualField(expected, *fromBuilderOpt, "sfNextPageMin"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(NFTokenPageTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(NFTokenPage{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(NFTokenPageTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(NFTokenPageBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(NFTokenPageTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const nFTokensValue = canonical_ARRAY(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + NFTokenPageBuilder builder{ + nFTokensValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasPreviousPageMin()); + EXPECT_FALSE(entry.getPreviousPageMin().has_value()); + EXPECT_FALSE(entry.hasNextPageMin()); + EXPECT_FALSE(entry.getNextPageMin().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/NegativeUNLTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/NegativeUNLTests.cpp new file mode 100644 index 0000000000..48ff060c11 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/NegativeUNLTests.cpp @@ -0,0 +1,251 @@ +// Auto-generated unit tests for ledger entry NegativeUNL + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(NegativeUNLTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const disabledValidatorsValue = canonical_ARRAY(); + auto const validatorToDisableValue = canonical_VL(); + auto const validatorToReEnableValue = canonical_VL(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + NegativeUNLBuilder builder{ + }; + + builder.setDisabledValidators(disabledValidatorsValue); + builder.setValidatorToDisable(validatorToDisableValue); + builder.setValidatorToReEnable(validatorToReEnableValue); + builder.setPreviousTxnID(previousTxnIDValue); + builder.setPreviousTxnLgrSeq(previousTxnLgrSeqValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = disabledValidatorsValue; + auto const actualOpt = entry.getDisabledValidators(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDisabledValidators"); + EXPECT_TRUE(entry.hasDisabledValidators()); + } + + { + auto const& expected = validatorToDisableValue; + auto const actualOpt = entry.getValidatorToDisable(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfValidatorToDisable"); + EXPECT_TRUE(entry.hasValidatorToDisable()); + } + + { + auto const& expected = validatorToReEnableValue; + auto const actualOpt = entry.getValidatorToReEnable(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfValidatorToReEnable"); + EXPECT_TRUE(entry.hasValidatorToReEnable()); + } + + { + auto const& expected = previousTxnIDValue; + auto const actualOpt = entry.getPreviousTxnID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnID"); + EXPECT_TRUE(entry.hasPreviousTxnID()); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actualOpt = entry.getPreviousTxnLgrSeq(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfPreviousTxnLgrSeq"); + EXPECT_TRUE(entry.hasPreviousTxnLgrSeq()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(NegativeUNLTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const disabledValidatorsValue = canonical_ARRAY(); + auto const validatorToDisableValue = canonical_VL(); + auto const validatorToReEnableValue = canonical_VL(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(NegativeUNL::entryType, index); + + sle->setFieldArray(sfDisabledValidators, disabledValidatorsValue); + sle->at(sfValidatorToDisable) = validatorToDisableValue; + sle->at(sfValidatorToReEnable) = validatorToReEnableValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + NegativeUNLBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + NegativeUNL entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = disabledValidatorsValue; + + auto const fromSleOpt = entryFromSle.getDisabledValidators(); + auto const fromBuilderOpt = entryFromBuilder.getDisabledValidators(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDisabledValidators"); + expectEqualField(expected, *fromBuilderOpt, "sfDisabledValidators"); + } + + { + auto const& expected = validatorToDisableValue; + + auto const fromSleOpt = entryFromSle.getValidatorToDisable(); + auto const fromBuilderOpt = entryFromBuilder.getValidatorToDisable(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfValidatorToDisable"); + expectEqualField(expected, *fromBuilderOpt, "sfValidatorToDisable"); + } + + { + auto const& expected = validatorToReEnableValue; + + auto const fromSleOpt = entryFromSle.getValidatorToReEnable(); + auto const fromBuilderOpt = entryFromBuilder.getValidatorToReEnable(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfValidatorToReEnable"); + expectEqualField(expected, *fromBuilderOpt, "sfValidatorToReEnable"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnID(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnID"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSleOpt = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilderOpt = entryFromBuilder.getPreviousTxnLgrSeq(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, *fromBuilderOpt, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(NegativeUNLTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(NegativeUNL{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(NegativeUNLTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(NegativeUNLBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(NegativeUNLTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + + NegativeUNLBuilder builder{ + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasDisabledValidators()); + EXPECT_FALSE(entry.getDisabledValidators().has_value()); + EXPECT_FALSE(entry.hasValidatorToDisable()); + EXPECT_FALSE(entry.getValidatorToDisable().has_value()); + EXPECT_FALSE(entry.hasValidatorToReEnable()); + EXPECT_FALSE(entry.getValidatorToReEnable().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnID()); + EXPECT_FALSE(entry.getPreviousTxnID().has_value()); + EXPECT_FALSE(entry.hasPreviousTxnLgrSeq()); + EXPECT_FALSE(entry.getPreviousTxnLgrSeq().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/OfferTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/OfferTests.cpp new file mode 100644 index 0000000000..5cb1bbd804 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/OfferTests.cpp @@ -0,0 +1,395 @@ +// Auto-generated unit tests for ledger entry Offer + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(OfferTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const takerPaysValue = canonical_AMOUNT(); + auto const takerGetsValue = canonical_AMOUNT(); + auto const bookDirectoryValue = canonical_UINT256(); + auto const bookNodeValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const expirationValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + auto const additionalBooksValue = canonical_ARRAY(); + + OfferBuilder builder{ + accountValue, + sequenceValue, + takerPaysValue, + takerGetsValue, + bookDirectoryValue, + bookNodeValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setExpiration(expirationValue); + builder.setDomainID(domainIDValue); + builder.setAdditionalBooks(additionalBooksValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = takerPaysValue; + auto const actual = entry.getTakerPays(); + expectEqualField(expected, actual, "sfTakerPays"); + } + + { + auto const& expected = takerGetsValue; + auto const actual = entry.getTakerGets(); + expectEqualField(expected, actual, "sfTakerGets"); + } + + { + auto const& expected = bookDirectoryValue; + auto const actual = entry.getBookDirectory(); + expectEqualField(expected, actual, "sfBookDirectory"); + } + + { + auto const& expected = bookNodeValue; + auto const actual = entry.getBookNode(); + expectEqualField(expected, actual, "sfBookNode"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = entry.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(entry.hasExpiration()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = entry.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(entry.hasDomainID()); + } + + { + auto const& expected = additionalBooksValue; + auto const actualOpt = entry.getAdditionalBooks(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAdditionalBooks"); + EXPECT_TRUE(entry.hasAdditionalBooks()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(OfferTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const takerPaysValue = canonical_AMOUNT(); + auto const takerGetsValue = canonical_AMOUNT(); + auto const bookDirectoryValue = canonical_UINT256(); + auto const bookNodeValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const expirationValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + auto const additionalBooksValue = canonical_ARRAY(); + + auto sle = std::make_shared(Offer::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfTakerPays) = takerPaysValue; + sle->at(sfTakerGets) = takerGetsValue; + sle->at(sfBookDirectory) = bookDirectoryValue; + sle->at(sfBookNode) = bookNodeValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfExpiration) = expirationValue; + sle->at(sfDomainID) = domainIDValue; + sle->setFieldArray(sfAdditionalBooks, additionalBooksValue); + + OfferBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Offer entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = takerPaysValue; + + auto const fromSle = entryFromSle.getTakerPays(); + auto const fromBuilder = entryFromBuilder.getTakerPays(); + + expectEqualField(expected, fromSle, "sfTakerPays"); + expectEqualField(expected, fromBuilder, "sfTakerPays"); + } + + { + auto const& expected = takerGetsValue; + + auto const fromSle = entryFromSle.getTakerGets(); + auto const fromBuilder = entryFromBuilder.getTakerGets(); + + expectEqualField(expected, fromSle, "sfTakerGets"); + expectEqualField(expected, fromBuilder, "sfTakerGets"); + } + + { + auto const& expected = bookDirectoryValue; + + auto const fromSle = entryFromSle.getBookDirectory(); + auto const fromBuilder = entryFromBuilder.getBookDirectory(); + + expectEqualField(expected, fromSle, "sfBookDirectory"); + expectEqualField(expected, fromBuilder, "sfBookDirectory"); + } + + { + auto const& expected = bookNodeValue; + + auto const fromSle = entryFromSle.getBookNode(); + auto const fromBuilder = entryFromBuilder.getBookNode(); + + expectEqualField(expected, fromSle, "sfBookNode"); + expectEqualField(expected, fromBuilder, "sfBookNode"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = expirationValue; + + auto const fromSleOpt = entryFromSle.getExpiration(); + auto const fromBuilderOpt = entryFromBuilder.getExpiration(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfExpiration"); + expectEqualField(expected, *fromBuilderOpt, "sfExpiration"); + } + + { + auto const& expected = domainIDValue; + + auto const fromSleOpt = entryFromSle.getDomainID(); + auto const fromBuilderOpt = entryFromBuilder.getDomainID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDomainID"); + expectEqualField(expected, *fromBuilderOpt, "sfDomainID"); + } + + { + auto const& expected = additionalBooksValue; + + auto const fromSleOpt = entryFromSle.getAdditionalBooks(); + auto const fromBuilderOpt = entryFromBuilder.getAdditionalBooks(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAdditionalBooks"); + expectEqualField(expected, *fromBuilderOpt, "sfAdditionalBooks"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(OfferTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Offer{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(OfferTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(OfferBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(OfferTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const takerPaysValue = canonical_AMOUNT(); + auto const takerGetsValue = canonical_AMOUNT(); + auto const bookDirectoryValue = canonical_UINT256(); + auto const bookNodeValue = canonical_UINT64(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + OfferBuilder builder{ + accountValue, + sequenceValue, + takerPaysValue, + takerGetsValue, + bookDirectoryValue, + bookNodeValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasExpiration()); + EXPECT_FALSE(entry.getExpiration().has_value()); + EXPECT_FALSE(entry.hasDomainID()); + EXPECT_FALSE(entry.getDomainID().has_value()); + EXPECT_FALSE(entry.hasAdditionalBooks()); + EXPECT_FALSE(entry.getAdditionalBooks().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/OracleTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/OracleTests.cpp new file mode 100644 index 0000000000..837fd576bf --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/OracleTests.cpp @@ -0,0 +1,346 @@ +// Auto-generated unit tests for ledger entry Oracle + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(OracleTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const oracleDocumentIDValue = canonical_UINT32(); + auto const providerValue = canonical_VL(); + auto const priceDataSeriesValue = canonical_ARRAY(); + auto const assetClassValue = canonical_VL(); + auto const lastUpdateTimeValue = canonical_UINT32(); + auto const uRIValue = canonical_VL(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + OracleBuilder builder{ + ownerValue, + providerValue, + priceDataSeriesValue, + assetClassValue, + lastUpdateTimeValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setOracleDocumentID(oracleDocumentIDValue); + builder.setURI(uRIValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = ownerValue; + auto const actual = entry.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = providerValue; + auto const actual = entry.getProvider(); + expectEqualField(expected, actual, "sfProvider"); + } + + { + auto const& expected = priceDataSeriesValue; + auto const actual = entry.getPriceDataSeries(); + expectEqualField(expected, actual, "sfPriceDataSeries"); + } + + { + auto const& expected = assetClassValue; + auto const actual = entry.getAssetClass(); + expectEqualField(expected, actual, "sfAssetClass"); + } + + { + auto const& expected = lastUpdateTimeValue; + auto const actual = entry.getLastUpdateTime(); + expectEqualField(expected, actual, "sfLastUpdateTime"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = oracleDocumentIDValue; + auto const actualOpt = entry.getOracleDocumentID(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOracleDocumentID"); + EXPECT_TRUE(entry.hasOracleDocumentID()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = entry.getURI(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(entry.hasURI()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(OracleTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const oracleDocumentIDValue = canonical_UINT32(); + auto const providerValue = canonical_VL(); + auto const priceDataSeriesValue = canonical_ARRAY(); + auto const assetClassValue = canonical_VL(); + auto const lastUpdateTimeValue = canonical_UINT32(); + auto const uRIValue = canonical_VL(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Oracle::entryType, index); + + sle->at(sfOwner) = ownerValue; + sle->at(sfOracleDocumentID) = oracleDocumentIDValue; + sle->at(sfProvider) = providerValue; + sle->setFieldArray(sfPriceDataSeries, priceDataSeriesValue); + sle->at(sfAssetClass) = assetClassValue; + sle->at(sfLastUpdateTime) = lastUpdateTimeValue; + sle->at(sfURI) = uRIValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + OracleBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Oracle entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = ownerValue; + + auto const fromSle = entryFromSle.getOwner(); + auto const fromBuilder = entryFromBuilder.getOwner(); + + expectEqualField(expected, fromSle, "sfOwner"); + expectEqualField(expected, fromBuilder, "sfOwner"); + } + + { + auto const& expected = providerValue; + + auto const fromSle = entryFromSle.getProvider(); + auto const fromBuilder = entryFromBuilder.getProvider(); + + expectEqualField(expected, fromSle, "sfProvider"); + expectEqualField(expected, fromBuilder, "sfProvider"); + } + + { + auto const& expected = priceDataSeriesValue; + + auto const fromSle = entryFromSle.getPriceDataSeries(); + auto const fromBuilder = entryFromBuilder.getPriceDataSeries(); + + expectEqualField(expected, fromSle, "sfPriceDataSeries"); + expectEqualField(expected, fromBuilder, "sfPriceDataSeries"); + } + + { + auto const& expected = assetClassValue; + + auto const fromSle = entryFromSle.getAssetClass(); + auto const fromBuilder = entryFromBuilder.getAssetClass(); + + expectEqualField(expected, fromSle, "sfAssetClass"); + expectEqualField(expected, fromBuilder, "sfAssetClass"); + } + + { + auto const& expected = lastUpdateTimeValue; + + auto const fromSle = entryFromSle.getLastUpdateTime(); + auto const fromBuilder = entryFromBuilder.getLastUpdateTime(); + + expectEqualField(expected, fromSle, "sfLastUpdateTime"); + expectEqualField(expected, fromBuilder, "sfLastUpdateTime"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = oracleDocumentIDValue; + + auto const fromSleOpt = entryFromSle.getOracleDocumentID(); + auto const fromBuilderOpt = entryFromBuilder.getOracleDocumentID(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOracleDocumentID"); + expectEqualField(expected, *fromBuilderOpt, "sfOracleDocumentID"); + } + + { + auto const& expected = uRIValue; + + auto const fromSleOpt = entryFromSle.getURI(); + auto const fromBuilderOpt = entryFromBuilder.getURI(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfURI"); + expectEqualField(expected, *fromBuilderOpt, "sfURI"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(OracleTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Oracle{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(OracleTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(OracleBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(OracleTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const providerValue = canonical_VL(); + auto const priceDataSeriesValue = canonical_ARRAY(); + auto const assetClassValue = canonical_VL(); + auto const lastUpdateTimeValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + OracleBuilder builder{ + ownerValue, + providerValue, + priceDataSeriesValue, + assetClassValue, + lastUpdateTimeValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasOracleDocumentID()); + EXPECT_FALSE(entry.getOracleDocumentID().has_value()); + EXPECT_FALSE(entry.hasURI()); + EXPECT_FALSE(entry.getURI().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/PayChannelTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/PayChannelTests.cpp new file mode 100644 index 0000000000..7c31252369 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/PayChannelTests.cpp @@ -0,0 +1,476 @@ +// Auto-generated unit tests for ledger entry PayChannel + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(PayChannelTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const amountValue = canonical_AMOUNT(); + auto const balanceValue = canonical_AMOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const settleDelayValue = canonical_UINT32(); + auto const expirationValue = canonical_UINT32(); + auto const cancelAfterValue = canonical_UINT32(); + auto const sourceTagValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const destinationNodeValue = canonical_UINT64(); + + PayChannelBuilder builder{ + accountValue, + destinationValue, + amountValue, + balanceValue, + publicKeyValue, + settleDelayValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setSequence(sequenceValue); + builder.setExpiration(expirationValue); + builder.setCancelAfter(cancelAfterValue); + builder.setSourceTag(sourceTagValue); + builder.setDestinationTag(destinationTagValue); + builder.setDestinationNode(destinationNodeValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = destinationValue; + auto const actual = entry.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = entry.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = balanceValue; + auto const actual = entry.getBalance(); + expectEqualField(expected, actual, "sfBalance"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = entry.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + { + auto const& expected = settleDelayValue; + auto const actual = entry.getSettleDelay(); + expectEqualField(expected, actual, "sfSettleDelay"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + auto const actualOpt = entry.getSequence(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfSequence"); + EXPECT_TRUE(entry.hasSequence()); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = entry.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(entry.hasExpiration()); + } + + { + auto const& expected = cancelAfterValue; + auto const actualOpt = entry.getCancelAfter(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfCancelAfter"); + EXPECT_TRUE(entry.hasCancelAfter()); + } + + { + auto const& expected = sourceTagValue; + auto const actualOpt = entry.getSourceTag(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfSourceTag"); + EXPECT_TRUE(entry.hasSourceTag()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = entry.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(entry.hasDestinationTag()); + } + + { + auto const& expected = destinationNodeValue; + auto const actualOpt = entry.getDestinationNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfDestinationNode"); + EXPECT_TRUE(entry.hasDestinationNode()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(PayChannelTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const amountValue = canonical_AMOUNT(); + auto const balanceValue = canonical_AMOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const settleDelayValue = canonical_UINT32(); + auto const expirationValue = canonical_UINT32(); + auto const cancelAfterValue = canonical_UINT32(); + auto const sourceTagValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const destinationNodeValue = canonical_UINT64(); + + auto sle = std::make_shared(PayChannel::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfDestination) = destinationValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfAmount) = amountValue; + sle->at(sfBalance) = balanceValue; + sle->at(sfPublicKey) = publicKeyValue; + sle->at(sfSettleDelay) = settleDelayValue; + sle->at(sfExpiration) = expirationValue; + sle->at(sfCancelAfter) = cancelAfterValue; + sle->at(sfSourceTag) = sourceTagValue; + sle->at(sfDestinationTag) = destinationTagValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfDestinationNode) = destinationNodeValue; + + PayChannelBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + PayChannel entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = destinationValue; + + auto const fromSle = entryFromSle.getDestination(); + auto const fromBuilder = entryFromBuilder.getDestination(); + + expectEqualField(expected, fromSle, "sfDestination"); + expectEqualField(expected, fromBuilder, "sfDestination"); + } + + { + auto const& expected = amountValue; + + auto const fromSle = entryFromSle.getAmount(); + auto const fromBuilder = entryFromBuilder.getAmount(); + + expectEqualField(expected, fromSle, "sfAmount"); + expectEqualField(expected, fromBuilder, "sfAmount"); + } + + { + auto const& expected = balanceValue; + + auto const fromSle = entryFromSle.getBalance(); + auto const fromBuilder = entryFromBuilder.getBalance(); + + expectEqualField(expected, fromSle, "sfBalance"); + expectEqualField(expected, fromBuilder, "sfBalance"); + } + + { + auto const& expected = publicKeyValue; + + auto const fromSle = entryFromSle.getPublicKey(); + auto const fromBuilder = entryFromBuilder.getPublicKey(); + + expectEqualField(expected, fromSle, "sfPublicKey"); + expectEqualField(expected, fromBuilder, "sfPublicKey"); + } + + { + auto const& expected = settleDelayValue; + + auto const fromSle = entryFromSle.getSettleDelay(); + auto const fromBuilder = entryFromBuilder.getSettleDelay(); + + expectEqualField(expected, fromSle, "sfSettleDelay"); + expectEqualField(expected, fromBuilder, "sfSettleDelay"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSleOpt = entryFromSle.getSequence(); + auto const fromBuilderOpt = entryFromBuilder.getSequence(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfSequence"); + expectEqualField(expected, *fromBuilderOpt, "sfSequence"); + } + + { + auto const& expected = expirationValue; + + auto const fromSleOpt = entryFromSle.getExpiration(); + auto const fromBuilderOpt = entryFromBuilder.getExpiration(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfExpiration"); + expectEqualField(expected, *fromBuilderOpt, "sfExpiration"); + } + + { + auto const& expected = cancelAfterValue; + + auto const fromSleOpt = entryFromSle.getCancelAfter(); + auto const fromBuilderOpt = entryFromBuilder.getCancelAfter(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfCancelAfter"); + expectEqualField(expected, *fromBuilderOpt, "sfCancelAfter"); + } + + { + auto const& expected = sourceTagValue; + + auto const fromSleOpt = entryFromSle.getSourceTag(); + auto const fromBuilderOpt = entryFromBuilder.getSourceTag(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfSourceTag"); + expectEqualField(expected, *fromBuilderOpt, "sfSourceTag"); + } + + { + auto const& expected = destinationTagValue; + + auto const fromSleOpt = entryFromSle.getDestinationTag(); + auto const fromBuilderOpt = entryFromBuilder.getDestinationTag(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDestinationTag"); + expectEqualField(expected, *fromBuilderOpt, "sfDestinationTag"); + } + + { + auto const& expected = destinationNodeValue; + + auto const fromSleOpt = entryFromSle.getDestinationNode(); + auto const fromBuilderOpt = entryFromBuilder.getDestinationNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfDestinationNode"); + expectEqualField(expected, *fromBuilderOpt, "sfDestinationNode"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(PayChannelTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(PayChannel{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(PayChannelTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(PayChannelBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(PayChannelTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const balanceValue = canonical_AMOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const settleDelayValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + PayChannelBuilder builder{ + accountValue, + destinationValue, + amountValue, + balanceValue, + publicKeyValue, + settleDelayValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasSequence()); + EXPECT_FALSE(entry.getSequence().has_value()); + EXPECT_FALSE(entry.hasExpiration()); + EXPECT_FALSE(entry.getExpiration().has_value()); + EXPECT_FALSE(entry.hasCancelAfter()); + EXPECT_FALSE(entry.getCancelAfter().has_value()); + EXPECT_FALSE(entry.hasSourceTag()); + EXPECT_FALSE(entry.getSourceTag().has_value()); + EXPECT_FALSE(entry.hasDestinationTag()); + EXPECT_FALSE(entry.getDestinationTag().has_value()); + EXPECT_FALSE(entry.hasDestinationNode()); + EXPECT_FALSE(entry.getDestinationNode().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/PermissionedDomainTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/PermissionedDomainTests.cpp new file mode 100644 index 0000000000..c448d064cf --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/PermissionedDomainTests.cpp @@ -0,0 +1,223 @@ +// Auto-generated unit tests for ledger entry PermissionedDomain + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(PermissionedDomainTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const acceptedCredentialsValue = canonical_ARRAY(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + PermissionedDomainBuilder builder{ + ownerValue, + sequenceValue, + acceptedCredentialsValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = ownerValue; + auto const actual = entry.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = acceptedCredentialsValue; + auto const actual = entry.getAcceptedCredentials(); + expectEqualField(expected, actual, "sfAcceptedCredentials"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(PermissionedDomainTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const sequenceValue = canonical_UINT32(); + auto const acceptedCredentialsValue = canonical_ARRAY(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(PermissionedDomain::entryType, index); + + sle->at(sfOwner) = ownerValue; + sle->at(sfSequence) = sequenceValue; + sle->setFieldArray(sfAcceptedCredentials, acceptedCredentialsValue); + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + PermissionedDomainBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + PermissionedDomain entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = ownerValue; + + auto const fromSle = entryFromSle.getOwner(); + auto const fromBuilder = entryFromBuilder.getOwner(); + + expectEqualField(expected, fromSle, "sfOwner"); + expectEqualField(expected, fromBuilder, "sfOwner"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = acceptedCredentialsValue; + + auto const fromSle = entryFromSle.getAcceptedCredentials(); + auto const fromBuilder = entryFromBuilder.getAcceptedCredentials(); + + expectEqualField(expected, fromSle, "sfAcceptedCredentials"); + expectEqualField(expected, fromBuilder, "sfAcceptedCredentials"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(PermissionedDomainTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(PermissionedDomain{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(PermissionedDomainTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(PermissionedDomainBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/RippleStateTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/RippleStateTests.cpp new file mode 100644 index 0000000000..a51ce55f6f --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/RippleStateTests.cpp @@ -0,0 +1,388 @@ +// Auto-generated unit tests for ledger entry RippleState + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(RippleStateTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const balanceValue = canonical_AMOUNT(); + auto const lowLimitValue = canonical_AMOUNT(); + auto const highLimitValue = canonical_AMOUNT(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const lowNodeValue = canonical_UINT64(); + auto const lowQualityInValue = canonical_UINT32(); + auto const lowQualityOutValue = canonical_UINT32(); + auto const highNodeValue = canonical_UINT64(); + auto const highQualityInValue = canonical_UINT32(); + auto const highQualityOutValue = canonical_UINT32(); + + RippleStateBuilder builder{ + balanceValue, + lowLimitValue, + highLimitValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setLowNode(lowNodeValue); + builder.setLowQualityIn(lowQualityInValue); + builder.setLowQualityOut(lowQualityOutValue); + builder.setHighNode(highNodeValue); + builder.setHighQualityIn(highQualityInValue); + builder.setHighQualityOut(highQualityOutValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = balanceValue; + auto const actual = entry.getBalance(); + expectEqualField(expected, actual, "sfBalance"); + } + + { + auto const& expected = lowLimitValue; + auto const actual = entry.getLowLimit(); + expectEqualField(expected, actual, "sfLowLimit"); + } + + { + auto const& expected = highLimitValue; + auto const actual = entry.getHighLimit(); + expectEqualField(expected, actual, "sfHighLimit"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = lowNodeValue; + auto const actualOpt = entry.getLowNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLowNode"); + EXPECT_TRUE(entry.hasLowNode()); + } + + { + auto const& expected = lowQualityInValue; + auto const actualOpt = entry.getLowQualityIn(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLowQualityIn"); + EXPECT_TRUE(entry.hasLowQualityIn()); + } + + { + auto const& expected = lowQualityOutValue; + auto const actualOpt = entry.getLowQualityOut(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLowQualityOut"); + EXPECT_TRUE(entry.hasLowQualityOut()); + } + + { + auto const& expected = highNodeValue; + auto const actualOpt = entry.getHighNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfHighNode"); + EXPECT_TRUE(entry.hasHighNode()); + } + + { + auto const& expected = highQualityInValue; + auto const actualOpt = entry.getHighQualityIn(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfHighQualityIn"); + EXPECT_TRUE(entry.hasHighQualityIn()); + } + + { + auto const& expected = highQualityOutValue; + auto const actualOpt = entry.getHighQualityOut(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfHighQualityOut"); + EXPECT_TRUE(entry.hasHighQualityOut()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(RippleStateTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const balanceValue = canonical_AMOUNT(); + auto const lowLimitValue = canonical_AMOUNT(); + auto const highLimitValue = canonical_AMOUNT(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const lowNodeValue = canonical_UINT64(); + auto const lowQualityInValue = canonical_UINT32(); + auto const lowQualityOutValue = canonical_UINT32(); + auto const highNodeValue = canonical_UINT64(); + auto const highQualityInValue = canonical_UINT32(); + auto const highQualityOutValue = canonical_UINT32(); + + auto sle = std::make_shared(RippleState::entryType, index); + + sle->at(sfBalance) = balanceValue; + sle->at(sfLowLimit) = lowLimitValue; + sle->at(sfHighLimit) = highLimitValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfLowNode) = lowNodeValue; + sle->at(sfLowQualityIn) = lowQualityInValue; + sle->at(sfLowQualityOut) = lowQualityOutValue; + sle->at(sfHighNode) = highNodeValue; + sle->at(sfHighQualityIn) = highQualityInValue; + sle->at(sfHighQualityOut) = highQualityOutValue; + + RippleStateBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + RippleState entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = balanceValue; + + auto const fromSle = entryFromSle.getBalance(); + auto const fromBuilder = entryFromBuilder.getBalance(); + + expectEqualField(expected, fromSle, "sfBalance"); + expectEqualField(expected, fromBuilder, "sfBalance"); + } + + { + auto const& expected = lowLimitValue; + + auto const fromSle = entryFromSle.getLowLimit(); + auto const fromBuilder = entryFromBuilder.getLowLimit(); + + expectEqualField(expected, fromSle, "sfLowLimit"); + expectEqualField(expected, fromBuilder, "sfLowLimit"); + } + + { + auto const& expected = highLimitValue; + + auto const fromSle = entryFromSle.getHighLimit(); + auto const fromBuilder = entryFromBuilder.getHighLimit(); + + expectEqualField(expected, fromSle, "sfHighLimit"); + expectEqualField(expected, fromBuilder, "sfHighLimit"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = lowNodeValue; + + auto const fromSleOpt = entryFromSle.getLowNode(); + auto const fromBuilderOpt = entryFromBuilder.getLowNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLowNode"); + expectEqualField(expected, *fromBuilderOpt, "sfLowNode"); + } + + { + auto const& expected = lowQualityInValue; + + auto const fromSleOpt = entryFromSle.getLowQualityIn(); + auto const fromBuilderOpt = entryFromBuilder.getLowQualityIn(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLowQualityIn"); + expectEqualField(expected, *fromBuilderOpt, "sfLowQualityIn"); + } + + { + auto const& expected = lowQualityOutValue; + + auto const fromSleOpt = entryFromSle.getLowQualityOut(); + auto const fromBuilderOpt = entryFromBuilder.getLowQualityOut(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLowQualityOut"); + expectEqualField(expected, *fromBuilderOpt, "sfLowQualityOut"); + } + + { + auto const& expected = highNodeValue; + + auto const fromSleOpt = entryFromSle.getHighNode(); + auto const fromBuilderOpt = entryFromBuilder.getHighNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfHighNode"); + expectEqualField(expected, *fromBuilderOpt, "sfHighNode"); + } + + { + auto const& expected = highQualityInValue; + + auto const fromSleOpt = entryFromSle.getHighQualityIn(); + auto const fromBuilderOpt = entryFromBuilder.getHighQualityIn(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfHighQualityIn"); + expectEqualField(expected, *fromBuilderOpt, "sfHighQualityIn"); + } + + { + auto const& expected = highQualityOutValue; + + auto const fromSleOpt = entryFromSle.getHighQualityOut(); + auto const fromBuilderOpt = entryFromBuilder.getHighQualityOut(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfHighQualityOut"); + expectEqualField(expected, *fromBuilderOpt, "sfHighQualityOut"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(RippleStateTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(RippleState{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(RippleStateTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(RippleStateBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(RippleStateTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const balanceValue = canonical_AMOUNT(); + auto const lowLimitValue = canonical_AMOUNT(); + auto const highLimitValue = canonical_AMOUNT(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + RippleStateBuilder builder{ + balanceValue, + lowLimitValue, + highLimitValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasLowNode()); + EXPECT_FALSE(entry.getLowNode().has_value()); + EXPECT_FALSE(entry.hasLowQualityIn()); + EXPECT_FALSE(entry.getLowQualityIn().has_value()); + EXPECT_FALSE(entry.hasLowQualityOut()); + EXPECT_FALSE(entry.getLowQualityOut().has_value()); + EXPECT_FALSE(entry.hasHighNode()); + EXPECT_FALSE(entry.getHighNode().has_value()); + EXPECT_FALSE(entry.hasHighQualityIn()); + EXPECT_FALSE(entry.getHighQualityIn().has_value()); + EXPECT_FALSE(entry.hasHighQualityOut()); + EXPECT_FALSE(entry.getHighQualityOut().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/SignerListTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/SignerListTests.cpp new file mode 100644 index 0000000000..5ec2c4e10d --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/SignerListTests.cpp @@ -0,0 +1,275 @@ +// Auto-generated unit tests for ledger entry SignerList + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(SignerListTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const signerQuorumValue = canonical_UINT32(); + auto const signerEntriesValue = canonical_ARRAY(); + auto const signerListIDValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + SignerListBuilder builder{ + ownerNodeValue, + signerQuorumValue, + signerEntriesValue, + signerListIDValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + builder.setOwner(ownerValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = signerQuorumValue; + auto const actual = entry.getSignerQuorum(); + expectEqualField(expected, actual, "sfSignerQuorum"); + } + + { + auto const& expected = signerEntriesValue; + auto const actual = entry.getSignerEntries(); + expectEqualField(expected, actual, "sfSignerEntries"); + } + + { + auto const& expected = signerListIDValue; + auto const actual = entry.getSignerListID(); + expectEqualField(expected, actual, "sfSignerListID"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = ownerValue; + auto const actualOpt = entry.getOwner(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOwner"); + EXPECT_TRUE(entry.hasOwner()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(SignerListTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const ownerValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const signerQuorumValue = canonical_UINT32(); + auto const signerEntriesValue = canonical_ARRAY(); + auto const signerListIDValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(SignerList::entryType, index); + + sle->at(sfOwner) = ownerValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfSignerQuorum) = signerQuorumValue; + sle->setFieldArray(sfSignerEntries, signerEntriesValue); + sle->at(sfSignerListID) = signerListIDValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + SignerListBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + SignerList entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = signerQuorumValue; + + auto const fromSle = entryFromSle.getSignerQuorum(); + auto const fromBuilder = entryFromBuilder.getSignerQuorum(); + + expectEqualField(expected, fromSle, "sfSignerQuorum"); + expectEqualField(expected, fromBuilder, "sfSignerQuorum"); + } + + { + auto const& expected = signerEntriesValue; + + auto const fromSle = entryFromSle.getSignerEntries(); + auto const fromBuilder = entryFromBuilder.getSignerEntries(); + + expectEqualField(expected, fromSle, "sfSignerEntries"); + expectEqualField(expected, fromBuilder, "sfSignerEntries"); + } + + { + auto const& expected = signerListIDValue; + + auto const fromSle = entryFromSle.getSignerListID(); + auto const fromBuilder = entryFromBuilder.getSignerListID(); + + expectEqualField(expected, fromSle, "sfSignerListID"); + expectEqualField(expected, fromBuilder, "sfSignerListID"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = ownerValue; + + auto const fromSleOpt = entryFromSle.getOwner(); + auto const fromBuilderOpt = entryFromBuilder.getOwner(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOwner"); + expectEqualField(expected, *fromBuilderOpt, "sfOwner"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(SignerListTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(SignerList{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(SignerListTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(SignerListBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(SignerListTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const ownerNodeValue = canonical_UINT64(); + auto const signerQuorumValue = canonical_UINT32(); + auto const signerEntriesValue = canonical_ARRAY(); + auto const signerListIDValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + SignerListBuilder builder{ + ownerNodeValue, + signerQuorumValue, + signerEntriesValue, + signerListIDValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasOwner()); + EXPECT_FALSE(entry.getOwner().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/TicketTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/TicketTests.cpp new file mode 100644 index 0000000000..1ac00288f0 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/TicketTests.cpp @@ -0,0 +1,209 @@ +// Auto-generated unit tests for ledger entry Ticket + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(TicketTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const ticketSequenceValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + TicketBuilder builder{ + accountValue, + ownerNodeValue, + ticketSequenceValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = ticketSequenceValue; + auto const actual = entry.getTicketSequence(); + expectEqualField(expected, actual, "sfTicketSequence"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(TicketTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const ticketSequenceValue = canonical_UINT32(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(Ticket::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfTicketSequence) = ticketSequenceValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + TicketBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Ticket entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = ticketSequenceValue; + + auto const fromSle = entryFromSle.getTicketSequence(); + auto const fromBuilder = entryFromBuilder.getTicketSequence(); + + expectEqualField(expected, fromSle, "sfTicketSequence"); + expectEqualField(expected, fromBuilder, "sfTicketSequence"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(TicketTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + CheckBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_ACCOUNT(), + canonical_AMOUNT(), + canonical_UINT32(), + canonical_UINT64(), + canonical_UINT64(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Ticket{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(TicketTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + CheckBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_ACCOUNT(), + canonical_AMOUNT(), + canonical_UINT32(), + canonical_UINT64(), + canonical_UINT64(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(TicketBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp new file mode 100644 index 0000000000..2697924d37 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp @@ -0,0 +1,476 @@ +// Auto-generated unit tests for ledger entry Vault + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(VaultTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const ownerValue = canonical_ACCOUNT(); + auto const accountValue = canonical_ACCOUNT(); + auto const dataValue = canonical_VL(); + auto const assetValue = canonical_ISSUE(); + auto const assetsTotalValue = canonical_NUMBER(); + auto const assetsAvailableValue = canonical_NUMBER(); + auto const assetsMaximumValue = canonical_NUMBER(); + auto const lossUnrealizedValue = canonical_NUMBER(); + auto const shareMPTIDValue = canonical_UINT192(); + auto const withdrawalPolicyValue = canonical_UINT8(); + auto const scaleValue = canonical_UINT8(); + + VaultBuilder builder{ + previousTxnIDValue, + previousTxnLgrSeqValue, + sequenceValue, + ownerNodeValue, + ownerValue, + accountValue, + assetValue, + shareMPTIDValue, + withdrawalPolicyValue + }; + + builder.setData(dataValue); + builder.setAssetsTotal(assetsTotalValue); + builder.setAssetsAvailable(assetsAvailableValue); + builder.setAssetsMaximum(assetsMaximumValue); + builder.setLossUnrealized(lossUnrealizedValue); + builder.setScale(scaleValue); + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + auto const actual = entry.getSequence(); + expectEqualField(expected, actual, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = ownerValue; + auto const actual = entry.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = assetValue; + auto const actual = entry.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = shareMPTIDValue; + auto const actual = entry.getShareMPTID(); + expectEqualField(expected, actual, "sfShareMPTID"); + } + + { + auto const& expected = withdrawalPolicyValue; + auto const actual = entry.getWithdrawalPolicy(); + expectEqualField(expected, actual, "sfWithdrawalPolicy"); + } + + { + auto const& expected = dataValue; + auto const actualOpt = entry.getData(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(entry.hasData()); + } + + { + auto const& expected = assetsTotalValue; + auto const actualOpt = entry.getAssetsTotal(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAssetsTotal"); + EXPECT_TRUE(entry.hasAssetsTotal()); + } + + { + auto const& expected = assetsAvailableValue; + auto const actualOpt = entry.getAssetsAvailable(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAssetsAvailable"); + EXPECT_TRUE(entry.hasAssetsAvailable()); + } + + { + auto const& expected = assetsMaximumValue; + auto const actualOpt = entry.getAssetsMaximum(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAssetsMaximum"); + EXPECT_TRUE(entry.hasAssetsMaximum()); + } + + { + auto const& expected = lossUnrealizedValue; + auto const actualOpt = entry.getLossUnrealized(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfLossUnrealized"); + EXPECT_TRUE(entry.hasLossUnrealized()); + } + + { + auto const& expected = scaleValue; + auto const actualOpt = entry.getScale(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfScale"); + EXPECT_TRUE(entry.hasScale()); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(VaultTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const ownerValue = canonical_ACCOUNT(); + auto const accountValue = canonical_ACCOUNT(); + auto const dataValue = canonical_VL(); + auto const assetValue = canonical_ISSUE(); + auto const assetsTotalValue = canonical_NUMBER(); + auto const assetsAvailableValue = canonical_NUMBER(); + auto const assetsMaximumValue = canonical_NUMBER(); + auto const lossUnrealizedValue = canonical_NUMBER(); + auto const shareMPTIDValue = canonical_UINT192(); + auto const withdrawalPolicyValue = canonical_UINT8(); + auto const scaleValue = canonical_UINT8(); + + auto sle = std::make_shared(Vault::entryType, index); + + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + sle->at(sfSequence) = sequenceValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfOwner) = ownerValue; + sle->at(sfAccount) = accountValue; + sle->at(sfData) = dataValue; + sle->at(sfAsset) = STIssue(sfAsset, assetValue); + sle->at(sfAssetsTotal) = assetsTotalValue; + sle->at(sfAssetsAvailable) = assetsAvailableValue; + sle->at(sfAssetsMaximum) = assetsMaximumValue; + sle->at(sfLossUnrealized) = lossUnrealizedValue; + sle->at(sfShareMPTID) = shareMPTIDValue; + sle->at(sfWithdrawalPolicy) = withdrawalPolicyValue; + sle->at(sfScale) = scaleValue; + + VaultBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + Vault entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + { + auto const& expected = sequenceValue; + + auto const fromSle = entryFromSle.getSequence(); + auto const fromBuilder = entryFromBuilder.getSequence(); + + expectEqualField(expected, fromSle, "sfSequence"); + expectEqualField(expected, fromBuilder, "sfSequence"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = ownerValue; + + auto const fromSle = entryFromSle.getOwner(); + auto const fromBuilder = entryFromBuilder.getOwner(); + + expectEqualField(expected, fromSle, "sfOwner"); + expectEqualField(expected, fromBuilder, "sfOwner"); + } + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = assetValue; + + auto const fromSle = entryFromSle.getAsset(); + auto const fromBuilder = entryFromBuilder.getAsset(); + + expectEqualField(expected, fromSle, "sfAsset"); + expectEqualField(expected, fromBuilder, "sfAsset"); + } + + { + auto const& expected = shareMPTIDValue; + + auto const fromSle = entryFromSle.getShareMPTID(); + auto const fromBuilder = entryFromBuilder.getShareMPTID(); + + expectEqualField(expected, fromSle, "sfShareMPTID"); + expectEqualField(expected, fromBuilder, "sfShareMPTID"); + } + + { + auto const& expected = withdrawalPolicyValue; + + auto const fromSle = entryFromSle.getWithdrawalPolicy(); + auto const fromBuilder = entryFromBuilder.getWithdrawalPolicy(); + + expectEqualField(expected, fromSle, "sfWithdrawalPolicy"); + expectEqualField(expected, fromBuilder, "sfWithdrawalPolicy"); + } + + { + auto const& expected = dataValue; + + auto const fromSleOpt = entryFromSle.getData(); + auto const fromBuilderOpt = entryFromBuilder.getData(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfData"); + expectEqualField(expected, *fromBuilderOpt, "sfData"); + } + + { + auto const& expected = assetsTotalValue; + + auto const fromSleOpt = entryFromSle.getAssetsTotal(); + auto const fromBuilderOpt = entryFromBuilder.getAssetsTotal(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAssetsTotal"); + expectEqualField(expected, *fromBuilderOpt, "sfAssetsTotal"); + } + + { + auto const& expected = assetsAvailableValue; + + auto const fromSleOpt = entryFromSle.getAssetsAvailable(); + auto const fromBuilderOpt = entryFromBuilder.getAssetsAvailable(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAssetsAvailable"); + expectEqualField(expected, *fromBuilderOpt, "sfAssetsAvailable"); + } + + { + auto const& expected = assetsMaximumValue; + + auto const fromSleOpt = entryFromSle.getAssetsMaximum(); + auto const fromBuilderOpt = entryFromBuilder.getAssetsMaximum(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAssetsMaximum"); + expectEqualField(expected, *fromBuilderOpt, "sfAssetsMaximum"); + } + + { + auto const& expected = lossUnrealizedValue; + + auto const fromSleOpt = entryFromSle.getLossUnrealized(); + auto const fromBuilderOpt = entryFromBuilder.getLossUnrealized(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfLossUnrealized"); + expectEqualField(expected, *fromBuilderOpt, "sfLossUnrealized"); + } + + { + auto const& expected = scaleValue; + + auto const fromSleOpt = entryFromSle.getScale(); + auto const fromBuilderOpt = entryFromBuilder.getScale(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfScale"); + expectEqualField(expected, *fromBuilderOpt, "sfScale"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(VaultTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(Vault{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(VaultTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(VaultBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(VaultTests, OptionalFieldsReturnNullopt) +{ + uint256 const index{3u}; + + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + auto const sequenceValue = canonical_UINT32(); + auto const ownerNodeValue = canonical_UINT64(); + auto const ownerValue = canonical_ACCOUNT(); + auto const accountValue = canonical_ACCOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const shareMPTIDValue = canonical_UINT192(); + auto const withdrawalPolicyValue = canonical_UINT8(); + + VaultBuilder builder{ + previousTxnIDValue, + previousTxnLgrSeqValue, + sequenceValue, + ownerNodeValue, + ownerValue, + accountValue, + assetValue, + shareMPTIDValue, + withdrawalPolicyValue + }; + + auto const entry = builder.build(index); + + // Verify optional fields are not present + EXPECT_FALSE(entry.hasData()); + EXPECT_FALSE(entry.getData().has_value()); + EXPECT_FALSE(entry.hasAssetsTotal()); + EXPECT_FALSE(entry.getAssetsTotal().has_value()); + EXPECT_FALSE(entry.hasAssetsAvailable()); + EXPECT_FALSE(entry.getAssetsAvailable().has_value()); + EXPECT_FALSE(entry.hasAssetsMaximum()); + EXPECT_FALSE(entry.getAssetsMaximum().has_value()); + EXPECT_FALSE(entry.hasLossUnrealized()); + EXPECT_FALSE(entry.getLossUnrealized().has_value()); + EXPECT_FALSE(entry.hasScale()); + EXPECT_FALSE(entry.getScale().has_value()); +} +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp new file mode 100644 index 0000000000..4b6979b86a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedClaimIDTests.cpp @@ -0,0 +1,283 @@ +// Auto-generated unit tests for ledger entry XChainOwnedClaimID + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(XChainOwnedClaimIDTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const xChainClaimAttestationsValue = canonical_ARRAY(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + XChainOwnedClaimIDBuilder builder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + otherChainSourceValue, + xChainClaimAttestationsValue, + signatureRewardValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = xChainBridgeValue; + auto const actual = entry.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = entry.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = entry.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + { + auto const& expected = xChainClaimAttestationsValue; + auto const actual = entry.getXChainClaimAttestations(); + expectEqualField(expected, actual, "sfXChainClaimAttestations"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = entry.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(XChainOwnedClaimIDTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const xChainClaimAttestationsValue = canonical_ARRAY(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(XChainOwnedClaimID::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfXChainBridge) = xChainBridgeValue; + sle->at(sfXChainClaimID) = xChainClaimIDValue; + sle->at(sfOtherChainSource) = otherChainSourceValue; + sle->setFieldArray(sfXChainClaimAttestations, xChainClaimAttestationsValue); + sle->at(sfSignatureReward) = signatureRewardValue; + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + XChainOwnedClaimIDBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + XChainOwnedClaimID entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = xChainBridgeValue; + + auto const fromSle = entryFromSle.getXChainBridge(); + auto const fromBuilder = entryFromBuilder.getXChainBridge(); + + expectEqualField(expected, fromSle, "sfXChainBridge"); + expectEqualField(expected, fromBuilder, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + + auto const fromSle = entryFromSle.getXChainClaimID(); + auto const fromBuilder = entryFromBuilder.getXChainClaimID(); + + expectEqualField(expected, fromSle, "sfXChainClaimID"); + expectEqualField(expected, fromBuilder, "sfXChainClaimID"); + } + + { + auto const& expected = otherChainSourceValue; + + auto const fromSle = entryFromSle.getOtherChainSource(); + auto const fromBuilder = entryFromBuilder.getOtherChainSource(); + + expectEqualField(expected, fromSle, "sfOtherChainSource"); + expectEqualField(expected, fromBuilder, "sfOtherChainSource"); + } + + { + auto const& expected = xChainClaimAttestationsValue; + + auto const fromSle = entryFromSle.getXChainClaimAttestations(); + auto const fromBuilder = entryFromBuilder.getXChainClaimAttestations(); + + expectEqualField(expected, fromSle, "sfXChainClaimAttestations"); + expectEqualField(expected, fromBuilder, "sfXChainClaimAttestations"); + } + + { + auto const& expected = signatureRewardValue; + + auto const fromSle = entryFromSle.getSignatureReward(); + auto const fromBuilder = entryFromBuilder.getSignatureReward(); + + expectEqualField(expected, fromSle, "sfSignatureReward"); + expectEqualField(expected, fromBuilder, "sfSignatureReward"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(XChainOwnedClaimIDTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(XChainOwnedClaimID{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(XChainOwnedClaimIDTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(XChainOwnedClaimIDBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp new file mode 100644 index 0000000000..0e4e1fb977 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/XChainOwnedCreateAccountClaimIDTests.cpp @@ -0,0 +1,243 @@ +// Auto-generated unit tests for ledger entry XChainOwnedCreateAccountClaimID + + +#include + +#include + +#include +#include +#include + +#include + +namespace xrpl::ledger_entries { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed for both the +// builder's STObject and the wrapper's SLE. +TEST(XChainOwnedCreateAccountClaimIDTests, BuilderSettersRoundTrip) +{ + uint256 const index{1u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const xChainCreateAccountAttestationsValue = canonical_ARRAY(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + XChainOwnedCreateAccountClaimIDBuilder builder{ + accountValue, + xChainBridgeValue, + xChainAccountCreateCountValue, + xChainCreateAccountAttestationsValue, + ownerNodeValue, + previousTxnIDValue, + previousTxnLgrSeqValue + }; + + + builder.setLedgerIndex(index); + builder.setFlags(0x1u); + + EXPECT_TRUE(builder.validate()); + + auto const entry = builder.build(index); + + EXPECT_TRUE(entry.validate()); + + { + auto const& expected = accountValue; + auto const actual = entry.getAccount(); + expectEqualField(expected, actual, "sfAccount"); + } + + { + auto const& expected = xChainBridgeValue; + auto const actual = entry.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainAccountCreateCountValue; + auto const actual = entry.getXChainAccountCreateCount(); + expectEqualField(expected, actual, "sfXChainAccountCreateCount"); + } + + { + auto const& expected = xChainCreateAccountAttestationsValue; + auto const actual = entry.getXChainCreateAccountAttestations(); + expectEqualField(expected, actual, "sfXChainCreateAccountAttestations"); + } + + { + auto const& expected = ownerNodeValue; + auto const actual = entry.getOwnerNode(); + expectEqualField(expected, actual, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + auto const actual = entry.getPreviousTxnID(); + expectEqualField(expected, actual, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + auto const actual = entry.getPreviousTxnLgrSeq(); + expectEqualField(expected, actual, "sfPreviousTxnLgrSeq"); + } + + EXPECT_TRUE(entry.hasLedgerIndex()); + auto const ledgerIndex = entry.getLedgerIndex(); + ASSERT_TRUE(ledgerIndex.has_value()); + EXPECT_EQ(*ledgerIndex, index); + EXPECT_EQ(entry.getKey(), index); +} + +// 2 & 4) Start from an SLE, set fields directly on it, construct a builder +// from that SLE, build a new wrapper, and verify all fields (and validate()). +TEST(XChainOwnedCreateAccountClaimIDTests, BuilderFromSleRoundTrip) +{ + uint256 const index{2u}; + + auto const accountValue = canonical_ACCOUNT(); + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const xChainCreateAccountAttestationsValue = canonical_ARRAY(); + auto const ownerNodeValue = canonical_UINT64(); + auto const previousTxnIDValue = canonical_UINT256(); + auto const previousTxnLgrSeqValue = canonical_UINT32(); + + auto sle = std::make_shared(XChainOwnedCreateAccountClaimID::entryType, index); + + sle->at(sfAccount) = accountValue; + sle->at(sfXChainBridge) = xChainBridgeValue; + sle->at(sfXChainAccountCreateCount) = xChainAccountCreateCountValue; + sle->setFieldArray(sfXChainCreateAccountAttestations, xChainCreateAccountAttestationsValue); + sle->at(sfOwnerNode) = ownerNodeValue; + sle->at(sfPreviousTxnID) = previousTxnIDValue; + sle->at(sfPreviousTxnLgrSeq) = previousTxnLgrSeqValue; + + XChainOwnedCreateAccountClaimIDBuilder builderFromSle{sle}; + EXPECT_TRUE(builderFromSle.validate()); + + auto const entryFromBuilder = builderFromSle.build(index); + + XChainOwnedCreateAccountClaimID entryFromSle{sle}; + EXPECT_TRUE(entryFromBuilder.validate()); + EXPECT_TRUE(entryFromSle.validate()); + + { + auto const& expected = accountValue; + + auto const fromSle = entryFromSle.getAccount(); + auto const fromBuilder = entryFromBuilder.getAccount(); + + expectEqualField(expected, fromSle, "sfAccount"); + expectEqualField(expected, fromBuilder, "sfAccount"); + } + + { + auto const& expected = xChainBridgeValue; + + auto const fromSle = entryFromSle.getXChainBridge(); + auto const fromBuilder = entryFromBuilder.getXChainBridge(); + + expectEqualField(expected, fromSle, "sfXChainBridge"); + expectEqualField(expected, fromBuilder, "sfXChainBridge"); + } + + { + auto const& expected = xChainAccountCreateCountValue; + + auto const fromSle = entryFromSle.getXChainAccountCreateCount(); + auto const fromBuilder = entryFromBuilder.getXChainAccountCreateCount(); + + expectEqualField(expected, fromSle, "sfXChainAccountCreateCount"); + expectEqualField(expected, fromBuilder, "sfXChainAccountCreateCount"); + } + + { + auto const& expected = xChainCreateAccountAttestationsValue; + + auto const fromSle = entryFromSle.getXChainCreateAccountAttestations(); + auto const fromBuilder = entryFromBuilder.getXChainCreateAccountAttestations(); + + expectEqualField(expected, fromSle, "sfXChainCreateAccountAttestations"); + expectEqualField(expected, fromBuilder, "sfXChainCreateAccountAttestations"); + } + + { + auto const& expected = ownerNodeValue; + + auto const fromSle = entryFromSle.getOwnerNode(); + auto const fromBuilder = entryFromBuilder.getOwnerNode(); + + expectEqualField(expected, fromSle, "sfOwnerNode"); + expectEqualField(expected, fromBuilder, "sfOwnerNode"); + } + + { + auto const& expected = previousTxnIDValue; + + auto const fromSle = entryFromSle.getPreviousTxnID(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnID(); + + expectEqualField(expected, fromSle, "sfPreviousTxnID"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnID"); + } + + { + auto const& expected = previousTxnLgrSeqValue; + + auto const fromSle = entryFromSle.getPreviousTxnLgrSeq(); + auto const fromBuilder = entryFromBuilder.getPreviousTxnLgrSeq(); + + expectEqualField(expected, fromSle, "sfPreviousTxnLgrSeq"); + expectEqualField(expected, fromBuilder, "sfPreviousTxnLgrSeq"); + } + + EXPECT_EQ(entryFromSle.getKey(), index); + EXPECT_EQ(entryFromBuilder.getKey(), index); +} + +// 3) Verify wrapper throws when constructed from wrong ledger entry type. +TEST(XChainOwnedCreateAccountClaimIDTests, WrapperThrowsOnWrongEntryType) +{ + uint256 const index{3u}; + + // Build a valid ledger entry of a different type + // Ticket requires: Account, OwnerNode, TicketSequence, PreviousTxnID, PreviousTxnLgrSeq + // Check requires: Account, Destination, SendMax, Sequence, OwnerNode, DestinationNode, PreviousTxnID, PreviousTxnLgrSeq + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(XChainOwnedCreateAccountClaimID{wrongEntry.getSle()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong ledger entry type. +TEST(XChainOwnedCreateAccountClaimIDTests, BuilderThrowsOnWrongEntryType) +{ + uint256 const index{4u}; + + // Build a valid ledger entry of a different type + TicketBuilder wrongBuilder{ + canonical_ACCOUNT(), + canonical_UINT64(), + canonical_UINT32(), + canonical_UINT256(), + canonical_UINT32()}; + auto wrongEntry = wrongBuilder.build(index); + + EXPECT_THROW(XChainOwnedCreateAccountClaimIDBuilder{wrongEntry.getSle()}, std::runtime_error); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/main.cpp b/src/tests/libxrpl/protocol_autogen/main.cpp new file mode 100644 index 0000000000..5142bbe08a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/main.cpp @@ -0,0 +1,8 @@ +#include + +int +main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMBidTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMBidTests.cpp new file mode 100644 index 0000000000..c9db0cabcf --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMBidTests.cpp @@ -0,0 +1,255 @@ +// Auto-generated unit tests for transaction AMMBid + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMBidTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMBid")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const bidMinValue = canonical_AMOUNT(); + auto const bidMaxValue = canonical_AMOUNT(); + auto const authAccountsValue = canonical_ARRAY(); + + AMMBidBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setBidMin(bidMinValue); + builder.setBidMax(bidMaxValue); + builder.setAuthAccounts(authAccountsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = tx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = bidMinValue; + auto const actualOpt = tx.getBidMin(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBidMin should be present"; + expectEqualField(expected, *actualOpt, "sfBidMin"); + EXPECT_TRUE(tx.hasBidMin()); + } + + { + auto const& expected = bidMaxValue; + auto const actualOpt = tx.getBidMax(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBidMax should be present"; + expectEqualField(expected, *actualOpt, "sfBidMax"); + EXPECT_TRUE(tx.hasBidMax()); + } + + { + auto const& expected = authAccountsValue; + auto const actualOpt = tx.getAuthAccounts(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAuthAccounts should be present"; + expectEqualField(expected, *actualOpt, "sfAuthAccounts"); + EXPECT_TRUE(tx.hasAuthAccounts()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMBidTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMBidFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const bidMinValue = canonical_AMOUNT(); + auto const bidMaxValue = canonical_AMOUNT(); + auto const authAccountsValue = canonical_ARRAY(); + + // Build an initial transaction + AMMBidBuilder initialBuilder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + initialBuilder.setBidMin(bidMinValue); + initialBuilder.setBidMax(bidMaxValue); + initialBuilder.setAuthAccounts(authAccountsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMBidBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = rebuiltTx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = bidMinValue; + auto const actualOpt = rebuiltTx.getBidMin(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBidMin should be present"; + expectEqualField(expected, *actualOpt, "sfBidMin"); + } + + { + auto const& expected = bidMaxValue; + auto const actualOpt = rebuiltTx.getBidMax(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBidMax should be present"; + expectEqualField(expected, *actualOpt, "sfBidMax"); + } + + { + auto const& expected = authAccountsValue; + auto const actualOpt = rebuiltTx.getAuthAccounts(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAuthAccounts should be present"; + expectEqualField(expected, *actualOpt, "sfAuthAccounts"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMBidTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMBid{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMBidTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMBidBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsAMMBidTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMBidNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + + AMMBidBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasBidMin()); + EXPECT_FALSE(tx.getBidMin().has_value()); + EXPECT_FALSE(tx.hasBidMax()); + EXPECT_FALSE(tx.getBidMax().has_value()); + EXPECT_FALSE(tx.hasAuthAccounts()); + EXPECT_FALSE(tx.getAuthAccounts().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMClawbackTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMClawbackTests.cpp new file mode 100644 index 0000000000..d01e840ce5 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMClawbackTests.cpp @@ -0,0 +1,231 @@ +// Auto-generated unit tests for transaction AMMClawback + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMClawbackTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMClawback")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const holderValue = canonical_ACCOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const amountValue = canonical_AMOUNT(); + + AMMClawbackBuilder builder{ + accountValue, + holderValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAmount(amountValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = holderValue; + auto const actual = tx.getHolder(); + expectEqualField(expected, actual, "sfHolder"); + } + + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = tx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMClawbackTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMClawbackFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const holderValue = canonical_ACCOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + AMMClawbackBuilder initialBuilder{ + accountValue, + holderValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + initialBuilder.setAmount(amountValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMClawbackBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = holderValue; + auto const actual = rebuiltTx.getHolder(); + expectEqualField(expected, actual, "sfHolder"); + } + + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = rebuiltTx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMClawbackTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMClawback{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMClawbackTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMClawbackBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsAMMClawbackTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMClawbackNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const holderValue = canonical_ACCOUNT(); + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + + AMMClawbackBuilder builder{ + accountValue, + holderValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMCreateTests.cpp new file mode 100644 index 0000000000..b55c9f377e --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMCreateTests.cpp @@ -0,0 +1,178 @@ +// Auto-generated unit tests for transaction AMMCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const amountValue = canonical_AMOUNT(); + auto const amount2Value = canonical_AMOUNT(); + auto const tradingFeeValue = canonical_UINT16(); + + AMMCreateBuilder builder{ + accountValue, + amountValue, + amount2Value, + tradingFeeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = amount2Value; + auto const actual = tx.getAmount2(); + expectEqualField(expected, actual, "sfAmount2"); + } + + { + auto const& expected = tradingFeeValue; + auto const actual = tx.getTradingFee(); + expectEqualField(expected, actual, "sfTradingFee"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const amountValue = canonical_AMOUNT(); + auto const amount2Value = canonical_AMOUNT(); + auto const tradingFeeValue = canonical_UINT16(); + + // Build an initial transaction + AMMCreateBuilder initialBuilder{ + accountValue, + amountValue, + amount2Value, + tradingFeeValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = amount2Value; + auto const actual = rebuiltTx.getAmount2(); + expectEqualField(expected, actual, "sfAmount2"); + } + + { + auto const& expected = tradingFeeValue; + auto const actual = rebuiltTx.getTradingFee(); + expectEqualField(expected, actual, "sfTradingFee"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMDeleteTests.cpp new file mode 100644 index 0000000000..774d993a1a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMDeleteTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction AMMDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + + AMMDeleteBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = tx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + + // Build an initial transaction + AMMDeleteBuilder initialBuilder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = rebuiltTx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMDepositTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMDepositTests.cpp new file mode 100644 index 0000000000..9917848f0a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMDepositTests.cpp @@ -0,0 +1,297 @@ +// Auto-generated unit tests for transaction AMMDeposit + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMDepositTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMDeposit")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const amountValue = canonical_AMOUNT(); + auto const amount2Value = canonical_AMOUNT(); + auto const ePriceValue = canonical_AMOUNT(); + auto const lPTokenOutValue = canonical_AMOUNT(); + auto const tradingFeeValue = canonical_UINT16(); + + AMMDepositBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAmount(amountValue); + builder.setAmount2(amount2Value); + builder.setEPrice(ePriceValue); + builder.setLPTokenOut(lPTokenOutValue); + builder.setTradingFee(tradingFeeValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = tx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + + { + auto const& expected = amount2Value; + auto const actualOpt = tx.getAmount2(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount2 should be present"; + expectEqualField(expected, *actualOpt, "sfAmount2"); + EXPECT_TRUE(tx.hasAmount2()); + } + + { + auto const& expected = ePriceValue; + auto const actualOpt = tx.getEPrice(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEPrice should be present"; + expectEqualField(expected, *actualOpt, "sfEPrice"); + EXPECT_TRUE(tx.hasEPrice()); + } + + { + auto const& expected = lPTokenOutValue; + auto const actualOpt = tx.getLPTokenOut(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLPTokenOut should be present"; + expectEqualField(expected, *actualOpt, "sfLPTokenOut"); + EXPECT_TRUE(tx.hasLPTokenOut()); + } + + { + auto const& expected = tradingFeeValue; + auto const actualOpt = tx.getTradingFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTradingFee should be present"; + expectEqualField(expected, *actualOpt, "sfTradingFee"); + EXPECT_TRUE(tx.hasTradingFee()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMDepositTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMDepositFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const amountValue = canonical_AMOUNT(); + auto const amount2Value = canonical_AMOUNT(); + auto const ePriceValue = canonical_AMOUNT(); + auto const lPTokenOutValue = canonical_AMOUNT(); + auto const tradingFeeValue = canonical_UINT16(); + + // Build an initial transaction + AMMDepositBuilder initialBuilder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + initialBuilder.setAmount(amountValue); + initialBuilder.setAmount2(amount2Value); + initialBuilder.setEPrice(ePriceValue); + initialBuilder.setLPTokenOut(lPTokenOutValue); + initialBuilder.setTradingFee(tradingFeeValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMDepositBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = rebuiltTx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + + { + auto const& expected = amount2Value; + auto const actualOpt = rebuiltTx.getAmount2(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount2 should be present"; + expectEqualField(expected, *actualOpt, "sfAmount2"); + } + + { + auto const& expected = ePriceValue; + auto const actualOpt = rebuiltTx.getEPrice(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEPrice should be present"; + expectEqualField(expected, *actualOpt, "sfEPrice"); + } + + { + auto const& expected = lPTokenOutValue; + auto const actualOpt = rebuiltTx.getLPTokenOut(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLPTokenOut should be present"; + expectEqualField(expected, *actualOpt, "sfLPTokenOut"); + } + + { + auto const& expected = tradingFeeValue; + auto const actualOpt = rebuiltTx.getTradingFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTradingFee should be present"; + expectEqualField(expected, *actualOpt, "sfTradingFee"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMDepositTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMDeposit{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMDepositTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMDepositBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsAMMDepositTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMDepositNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + + AMMDepositBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); + EXPECT_FALSE(tx.hasAmount2()); + EXPECT_FALSE(tx.getAmount2().has_value()); + EXPECT_FALSE(tx.hasEPrice()); + EXPECT_FALSE(tx.getEPrice().has_value()); + EXPECT_FALSE(tx.hasLPTokenOut()); + EXPECT_FALSE(tx.getLPTokenOut().has_value()); + EXPECT_FALSE(tx.hasTradingFee()); + EXPECT_FALSE(tx.getTradingFee().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMVoteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMVoteTests.cpp new file mode 100644 index 0000000000..6a47b7613e --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMVoteTests.cpp @@ -0,0 +1,178 @@ +// Auto-generated unit tests for transaction AMMVote + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMVoteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMVote")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const tradingFeeValue = canonical_UINT16(); + + AMMVoteBuilder builder{ + accountValue, + assetValue, + asset2Value, + tradingFeeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = tx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + { + auto const& expected = tradingFeeValue; + auto const actual = tx.getTradingFee(); + expectEqualField(expected, actual, "sfTradingFee"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMVoteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMVoteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const tradingFeeValue = canonical_UINT16(); + + // Build an initial transaction + AMMVoteBuilder initialBuilder{ + accountValue, + assetValue, + asset2Value, + tradingFeeValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMVoteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = rebuiltTx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + { + auto const& expected = tradingFeeValue; + auto const actual = rebuiltTx.getTradingFee(); + expectEqualField(expected, actual, "sfTradingFee"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMVoteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMVote{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMVoteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMVoteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AMMWithdrawTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AMMWithdrawTests.cpp new file mode 100644 index 0000000000..0fd529c282 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AMMWithdrawTests.cpp @@ -0,0 +1,276 @@ +// Auto-generated unit tests for transaction AMMWithdraw + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAMMWithdrawTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMWithdraw")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const amountValue = canonical_AMOUNT(); + auto const amount2Value = canonical_AMOUNT(); + auto const ePriceValue = canonical_AMOUNT(); + auto const lPTokenInValue = canonical_AMOUNT(); + + AMMWithdrawBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAmount(amountValue); + builder.setAmount2(amount2Value); + builder.setEPrice(ePriceValue); + builder.setLPTokenIn(lPTokenInValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = tx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + + { + auto const& expected = amount2Value; + auto const actualOpt = tx.getAmount2(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount2 should be present"; + expectEqualField(expected, *actualOpt, "sfAmount2"); + EXPECT_TRUE(tx.hasAmount2()); + } + + { + auto const& expected = ePriceValue; + auto const actualOpt = tx.getEPrice(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEPrice should be present"; + expectEqualField(expected, *actualOpt, "sfEPrice"); + EXPECT_TRUE(tx.hasEPrice()); + } + + { + auto const& expected = lPTokenInValue; + auto const actualOpt = tx.getLPTokenIn(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLPTokenIn should be present"; + expectEqualField(expected, *actualOpt, "sfLPTokenIn"); + EXPECT_TRUE(tx.hasLPTokenIn()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAMMWithdrawTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMWithdrawFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + auto const amountValue = canonical_AMOUNT(); + auto const amount2Value = canonical_AMOUNT(); + auto const ePriceValue = canonical_AMOUNT(); + auto const lPTokenInValue = canonical_AMOUNT(); + + // Build an initial transaction + AMMWithdrawBuilder initialBuilder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + initialBuilder.setAmount(amountValue); + initialBuilder.setAmount2(amount2Value); + initialBuilder.setEPrice(ePriceValue); + initialBuilder.setLPTokenIn(lPTokenInValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AMMWithdrawBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + { + auto const& expected = asset2Value; + auto const actual = rebuiltTx.getAsset2(); + expectEqualField(expected, actual, "sfAsset2"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + + { + auto const& expected = amount2Value; + auto const actualOpt = rebuiltTx.getAmount2(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount2 should be present"; + expectEqualField(expected, *actualOpt, "sfAmount2"); + } + + { + auto const& expected = ePriceValue; + auto const actualOpt = rebuiltTx.getEPrice(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEPrice should be present"; + expectEqualField(expected, *actualOpt, "sfEPrice"); + } + + { + auto const& expected = lPTokenInValue; + auto const actualOpt = rebuiltTx.getLPTokenIn(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLPTokenIn should be present"; + expectEqualField(expected, *actualOpt, "sfLPTokenIn"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAMMWithdrawTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMWithdraw{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAMMWithdrawTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AMMWithdrawBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsAMMWithdrawTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAMMWithdrawNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const assetValue = canonical_ISSUE(); + auto const asset2Value = canonical_ISSUE(); + + AMMWithdrawBuilder builder{ + accountValue, + assetValue, + asset2Value, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); + EXPECT_FALSE(tx.hasAmount2()); + EXPECT_FALSE(tx.getAmount2().has_value()); + EXPECT_FALSE(tx.hasEPrice()); + EXPECT_FALSE(tx.getEPrice().has_value()); + EXPECT_FALSE(tx.hasLPTokenIn()); + EXPECT_FALSE(tx.getLPTokenIn().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AccountDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AccountDeleteTests.cpp new file mode 100644 index 0000000000..0fb951221b --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AccountDeleteTests.cpp @@ -0,0 +1,216 @@ +// Auto-generated unit tests for transaction AccountDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAccountDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAccountDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + auto const credentialIDsValue = canonical_VECTOR256(); + + AccountDeleteBuilder builder{ + accountValue, + destinationValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDestinationTag(destinationTagValue); + builder.setCredentialIDs(credentialIDsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + // Verify optional fields + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = tx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + EXPECT_TRUE(tx.hasCredentialIDs()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAccountDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAccountDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + auto const credentialIDsValue = canonical_VECTOR256(); + + // Build an initial transaction + AccountDeleteBuilder initialBuilder{ + accountValue, + destinationValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDestinationTag(destinationTagValue); + initialBuilder.setCredentialIDs(credentialIDsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AccountDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + // Verify optional fields + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = rebuiltTx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAccountDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AccountDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAccountDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AccountDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsAccountDeleteTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAccountDeleteNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const destinationValue = canonical_ACCOUNT(); + + AccountDeleteBuilder builder{ + accountValue, + destinationValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); + EXPECT_FALSE(tx.hasCredentialIDs()); + EXPECT_FALSE(tx.getCredentialIDs().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/AccountSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/AccountSetTests.cpp new file mode 100644 index 0000000000..993fe55742 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/AccountSetTests.cpp @@ -0,0 +1,366 @@ +// Auto-generated unit tests for transaction AccountSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsAccountSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAccountSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const emailHashValue = canonical_UINT128(); + auto const walletLocatorValue = canonical_UINT256(); + auto const walletSizeValue = canonical_UINT32(); + auto const messageKeyValue = canonical_VL(); + auto const domainValue = canonical_VL(); + auto const transferRateValue = canonical_UINT32(); + auto const setFlagValue = canonical_UINT32(); + auto const clearFlagValue = canonical_UINT32(); + auto const tickSizeValue = canonical_UINT8(); + auto const nFTokenMinterValue = canonical_ACCOUNT(); + + AccountSetBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setEmailHash(emailHashValue); + builder.setWalletLocator(walletLocatorValue); + builder.setWalletSize(walletSizeValue); + builder.setMessageKey(messageKeyValue); + builder.setDomain(domainValue); + builder.setTransferRate(transferRateValue); + builder.setSetFlag(setFlagValue); + builder.setClearFlag(clearFlagValue); + builder.setTickSize(tickSizeValue); + builder.setNFTokenMinter(nFTokenMinterValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = emailHashValue; + auto const actualOpt = tx.getEmailHash(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEmailHash should be present"; + expectEqualField(expected, *actualOpt, "sfEmailHash"); + EXPECT_TRUE(tx.hasEmailHash()); + } + + { + auto const& expected = walletLocatorValue; + auto const actualOpt = tx.getWalletLocator(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletLocator should be present"; + expectEqualField(expected, *actualOpt, "sfWalletLocator"); + EXPECT_TRUE(tx.hasWalletLocator()); + } + + { + auto const& expected = walletSizeValue; + auto const actualOpt = tx.getWalletSize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletSize should be present"; + expectEqualField(expected, *actualOpt, "sfWalletSize"); + EXPECT_TRUE(tx.hasWalletSize()); + } + + { + auto const& expected = messageKeyValue; + auto const actualOpt = tx.getMessageKey(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMessageKey should be present"; + expectEqualField(expected, *actualOpt, "sfMessageKey"); + EXPECT_TRUE(tx.hasMessageKey()); + } + + { + auto const& expected = domainValue; + auto const actualOpt = tx.getDomain(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomain should be present"; + expectEqualField(expected, *actualOpt, "sfDomain"); + EXPECT_TRUE(tx.hasDomain()); + } + + { + auto const& expected = transferRateValue; + auto const actualOpt = tx.getTransferRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferRate should be present"; + expectEqualField(expected, *actualOpt, "sfTransferRate"); + EXPECT_TRUE(tx.hasTransferRate()); + } + + { + auto const& expected = setFlagValue; + auto const actualOpt = tx.getSetFlag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSetFlag should be present"; + expectEqualField(expected, *actualOpt, "sfSetFlag"); + EXPECT_TRUE(tx.hasSetFlag()); + } + + { + auto const& expected = clearFlagValue; + auto const actualOpt = tx.getClearFlag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfClearFlag should be present"; + expectEqualField(expected, *actualOpt, "sfClearFlag"); + EXPECT_TRUE(tx.hasClearFlag()); + } + + { + auto const& expected = tickSizeValue; + auto const actualOpt = tx.getTickSize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTickSize should be present"; + expectEqualField(expected, *actualOpt, "sfTickSize"); + EXPECT_TRUE(tx.hasTickSize()); + } + + { + auto const& expected = nFTokenMinterValue; + auto const actualOpt = tx.getNFTokenMinter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenMinter should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenMinter"); + EXPECT_TRUE(tx.hasNFTokenMinter()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsAccountSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAccountSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const emailHashValue = canonical_UINT128(); + auto const walletLocatorValue = canonical_UINT256(); + auto const walletSizeValue = canonical_UINT32(); + auto const messageKeyValue = canonical_VL(); + auto const domainValue = canonical_VL(); + auto const transferRateValue = canonical_UINT32(); + auto const setFlagValue = canonical_UINT32(); + auto const clearFlagValue = canonical_UINT32(); + auto const tickSizeValue = canonical_UINT8(); + auto const nFTokenMinterValue = canonical_ACCOUNT(); + + // Build an initial transaction + AccountSetBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setEmailHash(emailHashValue); + initialBuilder.setWalletLocator(walletLocatorValue); + initialBuilder.setWalletSize(walletSizeValue); + initialBuilder.setMessageKey(messageKeyValue); + initialBuilder.setDomain(domainValue); + initialBuilder.setTransferRate(transferRateValue); + initialBuilder.setSetFlag(setFlagValue); + initialBuilder.setClearFlag(clearFlagValue); + initialBuilder.setTickSize(tickSizeValue); + initialBuilder.setNFTokenMinter(nFTokenMinterValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + AccountSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = emailHashValue; + auto const actualOpt = rebuiltTx.getEmailHash(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEmailHash should be present"; + expectEqualField(expected, *actualOpt, "sfEmailHash"); + } + + { + auto const& expected = walletLocatorValue; + auto const actualOpt = rebuiltTx.getWalletLocator(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletLocator should be present"; + expectEqualField(expected, *actualOpt, "sfWalletLocator"); + } + + { + auto const& expected = walletSizeValue; + auto const actualOpt = rebuiltTx.getWalletSize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletSize should be present"; + expectEqualField(expected, *actualOpt, "sfWalletSize"); + } + + { + auto const& expected = messageKeyValue; + auto const actualOpt = rebuiltTx.getMessageKey(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMessageKey should be present"; + expectEqualField(expected, *actualOpt, "sfMessageKey"); + } + + { + auto const& expected = domainValue; + auto const actualOpt = rebuiltTx.getDomain(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomain should be present"; + expectEqualField(expected, *actualOpt, "sfDomain"); + } + + { + auto const& expected = transferRateValue; + auto const actualOpt = rebuiltTx.getTransferRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferRate should be present"; + expectEqualField(expected, *actualOpt, "sfTransferRate"); + } + + { + auto const& expected = setFlagValue; + auto const actualOpt = rebuiltTx.getSetFlag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSetFlag should be present"; + expectEqualField(expected, *actualOpt, "sfSetFlag"); + } + + { + auto const& expected = clearFlagValue; + auto const actualOpt = rebuiltTx.getClearFlag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfClearFlag should be present"; + expectEqualField(expected, *actualOpt, "sfClearFlag"); + } + + { + auto const& expected = tickSizeValue; + auto const actualOpt = rebuiltTx.getTickSize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTickSize should be present"; + expectEqualField(expected, *actualOpt, "sfTickSize"); + } + + { + auto const& expected = nFTokenMinterValue; + auto const actualOpt = rebuiltTx.getNFTokenMinter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenMinter should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenMinter"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsAccountSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + OfferCancelBuilder wrongBuilder{account, canonical_UINT32(), 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AccountSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsAccountSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + OfferCancelBuilder wrongBuilder{account, canonical_UINT32(), 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(AccountSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsAccountSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testAccountSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + AccountSetBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasEmailHash()); + EXPECT_FALSE(tx.getEmailHash().has_value()); + EXPECT_FALSE(tx.hasWalletLocator()); + EXPECT_FALSE(tx.getWalletLocator().has_value()); + EXPECT_FALSE(tx.hasWalletSize()); + EXPECT_FALSE(tx.getWalletSize().has_value()); + EXPECT_FALSE(tx.hasMessageKey()); + EXPECT_FALSE(tx.getMessageKey().has_value()); + EXPECT_FALSE(tx.hasDomain()); + EXPECT_FALSE(tx.getDomain().has_value()); + EXPECT_FALSE(tx.hasTransferRate()); + EXPECT_FALSE(tx.getTransferRate().has_value()); + EXPECT_FALSE(tx.hasSetFlag()); + EXPECT_FALSE(tx.getSetFlag().has_value()); + EXPECT_FALSE(tx.hasClearFlag()); + EXPECT_FALSE(tx.getClearFlag().has_value()); + EXPECT_FALSE(tx.hasTickSize()); + EXPECT_FALSE(tx.getTickSize().has_value()); + EXPECT_FALSE(tx.hasNFTokenMinter()); + EXPECT_FALSE(tx.getNFTokenMinter().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/BatchTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/BatchTests.cpp new file mode 100644 index 0000000000..c6818a26d7 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/BatchTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction Batch + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsBatchTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testBatch")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const rawTransactionsValue = canonical_ARRAY(); + auto const batchSignersValue = canonical_ARRAY(); + + BatchBuilder builder{ + accountValue, + rawTransactionsValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setBatchSigners(batchSignersValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = rawTransactionsValue; + auto const actual = tx.getRawTransactions(); + expectEqualField(expected, actual, "sfRawTransactions"); + } + + // Verify optional fields + { + auto const& expected = batchSignersValue; + auto const actualOpt = tx.getBatchSigners(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBatchSigners should be present"; + expectEqualField(expected, *actualOpt, "sfBatchSigners"); + EXPECT_TRUE(tx.hasBatchSigners()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsBatchTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testBatchFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const rawTransactionsValue = canonical_ARRAY(); + auto const batchSignersValue = canonical_ARRAY(); + + // Build an initial transaction + BatchBuilder initialBuilder{ + accountValue, + rawTransactionsValue, + sequenceValue, + feeValue + }; + + initialBuilder.setBatchSigners(batchSignersValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + BatchBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = rawTransactionsValue; + auto const actual = rebuiltTx.getRawTransactions(); + expectEqualField(expected, actual, "sfRawTransactions"); + } + + // Verify optional fields + { + auto const& expected = batchSignersValue; + auto const actualOpt = rebuiltTx.getBatchSigners(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBatchSigners should be present"; + expectEqualField(expected, *actualOpt, "sfBatchSigners"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsBatchTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(Batch{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsBatchTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(BatchBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsBatchTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testBatchNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const rawTransactionsValue = canonical_ARRAY(); + + BatchBuilder builder{ + accountValue, + rawTransactionsValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasBatchSigners()); + EXPECT_FALSE(tx.getBatchSigners().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/CheckCancelTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/CheckCancelTests.cpp new file mode 100644 index 0000000000..afdc2d6d66 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/CheckCancelTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction CheckCancel + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsCheckCancelTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCancel")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const checkIDValue = canonical_UINT256(); + + CheckCancelBuilder builder{ + accountValue, + checkIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = checkIDValue; + auto const actual = tx.getCheckID(); + expectEqualField(expected, actual, "sfCheckID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsCheckCancelTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCancelFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const checkIDValue = canonical_UINT256(); + + // Build an initial transaction + CheckCancelBuilder initialBuilder{ + accountValue, + checkIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + CheckCancelBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = checkIDValue; + auto const actual = rebuiltTx.getCheckID(); + expectEqualField(expected, actual, "sfCheckID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsCheckCancelTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CheckCancel{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsCheckCancelTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CheckCancelBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/CheckCashTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/CheckCashTests.cpp new file mode 100644 index 0000000000..b8c4dccd55 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/CheckCashTests.cpp @@ -0,0 +1,216 @@ +// Auto-generated unit tests for transaction CheckCash + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsCheckCashTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCash")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const checkIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const deliverMinValue = canonical_AMOUNT(); + + CheckCashBuilder builder{ + accountValue, + checkIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAmount(amountValue); + builder.setDeliverMin(deliverMinValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = checkIDValue; + auto const actual = tx.getCheckID(); + expectEqualField(expected, actual, "sfCheckID"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + + { + auto const& expected = deliverMinValue; + auto const actualOpt = tx.getDeliverMin(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDeliverMin should be present"; + expectEqualField(expected, *actualOpt, "sfDeliverMin"); + EXPECT_TRUE(tx.hasDeliverMin()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsCheckCashTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCashFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const checkIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const deliverMinValue = canonical_AMOUNT(); + + // Build an initial transaction + CheckCashBuilder initialBuilder{ + accountValue, + checkIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAmount(amountValue); + initialBuilder.setDeliverMin(deliverMinValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + CheckCashBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = checkIDValue; + auto const actual = rebuiltTx.getCheckID(); + expectEqualField(expected, actual, "sfCheckID"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + + { + auto const& expected = deliverMinValue; + auto const actualOpt = rebuiltTx.getDeliverMin(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDeliverMin should be present"; + expectEqualField(expected, *actualOpt, "sfDeliverMin"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsCheckCashTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CheckCash{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsCheckCashTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CheckCashBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsCheckCashTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCashNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const checkIDValue = canonical_UINT256(); + + CheckCashBuilder builder{ + accountValue, + checkIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); + EXPECT_FALSE(tx.hasDeliverMin()); + EXPECT_FALSE(tx.getDeliverMin().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/CheckCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/CheckCreateTests.cpp new file mode 100644 index 0000000000..9b8a831913 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/CheckCreateTests.cpp @@ -0,0 +1,255 @@ +// Auto-generated unit tests for transaction CheckCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsCheckCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const expirationValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const invoiceIDValue = canonical_UINT256(); + + CheckCreateBuilder builder{ + accountValue, + destinationValue, + sendMaxValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setExpiration(expirationValue); + builder.setDestinationTag(destinationTagValue); + builder.setInvoiceID(invoiceIDValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = sendMaxValue; + auto const actual = tx.getSendMax(); + expectEqualField(expected, actual, "sfSendMax"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = tx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(tx.hasExpiration()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + + { + auto const& expected = invoiceIDValue; + auto const actualOpt = tx.getInvoiceID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfInvoiceID should be present"; + expectEqualField(expected, *actualOpt, "sfInvoiceID"); + EXPECT_TRUE(tx.hasInvoiceID()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsCheckCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const expirationValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + auto const invoiceIDValue = canonical_UINT256(); + + // Build an initial transaction + CheckCreateBuilder initialBuilder{ + accountValue, + destinationValue, + sendMaxValue, + sequenceValue, + feeValue + }; + + initialBuilder.setExpiration(expirationValue); + initialBuilder.setDestinationTag(destinationTagValue); + initialBuilder.setInvoiceID(invoiceIDValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + CheckCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = sendMaxValue; + auto const actual = rebuiltTx.getSendMax(); + expectEqualField(expected, actual, "sfSendMax"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = rebuiltTx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + + { + auto const& expected = invoiceIDValue; + auto const actualOpt = rebuiltTx.getInvoiceID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfInvoiceID should be present"; + expectEqualField(expected, *actualOpt, "sfInvoiceID"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsCheckCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CheckCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsCheckCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CheckCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsCheckCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCheckCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const destinationValue = canonical_ACCOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + + CheckCreateBuilder builder{ + accountValue, + destinationValue, + sendMaxValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasExpiration()); + EXPECT_FALSE(tx.getExpiration().has_value()); + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); + EXPECT_FALSE(tx.hasInvoiceID()); + EXPECT_FALSE(tx.getInvoiceID().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/ClawbackTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/ClawbackTests.cpp new file mode 100644 index 0000000000..2f9b7f1e3a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/ClawbackTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction Clawback + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsClawbackTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testClawback")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const amountValue = canonical_AMOUNT(); + auto const holderValue = canonical_ACCOUNT(); + + ClawbackBuilder builder{ + accountValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setHolder(holderValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = holderValue; + auto const actualOpt = tx.getHolder(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfHolder should be present"; + expectEqualField(expected, *actualOpt, "sfHolder"); + EXPECT_TRUE(tx.hasHolder()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsClawbackTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testClawbackFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const amountValue = canonical_AMOUNT(); + auto const holderValue = canonical_ACCOUNT(); + + // Build an initial transaction + ClawbackBuilder initialBuilder{ + accountValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setHolder(holderValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + ClawbackBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = holderValue; + auto const actualOpt = rebuiltTx.getHolder(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfHolder should be present"; + expectEqualField(expected, *actualOpt, "sfHolder"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsClawbackTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(Clawback{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsClawbackTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(ClawbackBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsClawbackTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testClawbackNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const amountValue = canonical_AMOUNT(); + + ClawbackBuilder builder{ + accountValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasHolder()); + EXPECT_FALSE(tx.getHolder().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/CredentialAcceptTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/CredentialAcceptTests.cpp new file mode 100644 index 0000000000..5ae9c8a181 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/CredentialAcceptTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction CredentialAccept + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsCredentialAcceptTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialAccept")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + + CredentialAcceptBuilder builder{ + accountValue, + issuerValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = issuerValue; + auto const actual = tx.getIssuer(); + expectEqualField(expected, actual, "sfIssuer"); + } + + { + auto const& expected = credentialTypeValue; + auto const actual = tx.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsCredentialAcceptTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialAcceptFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + + // Build an initial transaction + CredentialAcceptBuilder initialBuilder{ + accountValue, + issuerValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + CredentialAcceptBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = issuerValue; + auto const actual = rebuiltTx.getIssuer(); + expectEqualField(expected, actual, "sfIssuer"); + } + + { + auto const& expected = credentialTypeValue; + auto const actual = rebuiltTx.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsCredentialAcceptTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CredentialAccept{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsCredentialAcceptTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CredentialAcceptBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/CredentialCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/CredentialCreateTests.cpp new file mode 100644 index 0000000000..0bfa9def33 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/CredentialCreateTests.cpp @@ -0,0 +1,234 @@ +// Auto-generated unit tests for transaction CredentialCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsCredentialCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const subjectValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + auto const expirationValue = canonical_UINT32(); + auto const uRIValue = canonical_VL(); + + CredentialCreateBuilder builder{ + accountValue, + subjectValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setExpiration(expirationValue); + builder.setURI(uRIValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = subjectValue; + auto const actual = tx.getSubject(); + expectEqualField(expected, actual, "sfSubject"); + } + + { + auto const& expected = credentialTypeValue; + auto const actual = tx.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = tx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(tx.hasExpiration()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = tx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(tx.hasURI()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsCredentialCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const subjectValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + auto const expirationValue = canonical_UINT32(); + auto const uRIValue = canonical_VL(); + + // Build an initial transaction + CredentialCreateBuilder initialBuilder{ + accountValue, + subjectValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + initialBuilder.setExpiration(expirationValue); + initialBuilder.setURI(uRIValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + CredentialCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = subjectValue; + auto const actual = rebuiltTx.getSubject(); + expectEqualField(expected, actual, "sfSubject"); + } + + { + auto const& expected = credentialTypeValue; + auto const actual = rebuiltTx.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = rebuiltTx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = rebuiltTx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsCredentialCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CredentialCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsCredentialCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CredentialCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsCredentialCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const subjectValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + + CredentialCreateBuilder builder{ + accountValue, + subjectValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasExpiration()); + EXPECT_FALSE(tx.getExpiration().has_value()); + EXPECT_FALSE(tx.hasURI()); + EXPECT_FALSE(tx.getURI().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/CredentialDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/CredentialDeleteTests.cpp new file mode 100644 index 0000000000..26bba2ba1a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/CredentialDeleteTests.cpp @@ -0,0 +1,216 @@ +// Auto-generated unit tests for transaction CredentialDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsCredentialDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const subjectValue = canonical_ACCOUNT(); + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + + CredentialDeleteBuilder builder{ + accountValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setSubject(subjectValue); + builder.setIssuer(issuerValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = credentialTypeValue; + auto const actual = tx.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + // Verify optional fields + { + auto const& expected = subjectValue; + auto const actualOpt = tx.getSubject(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSubject should be present"; + expectEqualField(expected, *actualOpt, "sfSubject"); + EXPECT_TRUE(tx.hasSubject()); + } + + { + auto const& expected = issuerValue; + auto const actualOpt = tx.getIssuer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfIssuer should be present"; + expectEqualField(expected, *actualOpt, "sfIssuer"); + EXPECT_TRUE(tx.hasIssuer()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsCredentialDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const subjectValue = canonical_ACCOUNT(); + auto const issuerValue = canonical_ACCOUNT(); + auto const credentialTypeValue = canonical_VL(); + + // Build an initial transaction + CredentialDeleteBuilder initialBuilder{ + accountValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + initialBuilder.setSubject(subjectValue); + initialBuilder.setIssuer(issuerValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + CredentialDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = credentialTypeValue; + auto const actual = rebuiltTx.getCredentialType(); + expectEqualField(expected, actual, "sfCredentialType"); + } + + // Verify optional fields + { + auto const& expected = subjectValue; + auto const actualOpt = rebuiltTx.getSubject(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSubject should be present"; + expectEqualField(expected, *actualOpt, "sfSubject"); + } + + { + auto const& expected = issuerValue; + auto const actualOpt = rebuiltTx.getIssuer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfIssuer should be present"; + expectEqualField(expected, *actualOpt, "sfIssuer"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsCredentialDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CredentialDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsCredentialDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(CredentialDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsCredentialDeleteTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testCredentialDeleteNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const credentialTypeValue = canonical_VL(); + + CredentialDeleteBuilder builder{ + accountValue, + credentialTypeValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasSubject()); + EXPECT_FALSE(tx.getSubject().has_value()); + EXPECT_FALSE(tx.hasIssuer()); + EXPECT_FALSE(tx.getIssuer().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/DIDDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/DIDDeleteTests.cpp new file mode 100644 index 0000000000..e60ef99fb1 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/DIDDeleteTests.cpp @@ -0,0 +1,130 @@ +// Auto-generated unit tests for transaction DIDDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsDIDDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDIDDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + + DIDDeleteBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsDIDDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDIDDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + + // Build an initial transaction + DIDDeleteBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + DIDDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsDIDDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DIDDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsDIDDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DIDDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/DIDSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/DIDSetTests.cpp new file mode 100644 index 0000000000..07215e6966 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/DIDSetTests.cpp @@ -0,0 +1,219 @@ +// Auto-generated unit tests for transaction DIDSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsDIDSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDIDSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const dIDDocumentValue = canonical_VL(); + auto const uRIValue = canonical_VL(); + auto const dataValue = canonical_VL(); + + DIDSetBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDIDDocument(dIDDocumentValue); + builder.setURI(uRIValue); + builder.setData(dataValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = dIDDocumentValue; + auto const actualOpt = tx.getDIDDocument(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDIDDocument should be present"; + expectEqualField(expected, *actualOpt, "sfDIDDocument"); + EXPECT_TRUE(tx.hasDIDDocument()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = tx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(tx.hasURI()); + } + + { + auto const& expected = dataValue; + auto const actualOpt = tx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(tx.hasData()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsDIDSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDIDSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const dIDDocumentValue = canonical_VL(); + auto const uRIValue = canonical_VL(); + auto const dataValue = canonical_VL(); + + // Build an initial transaction + DIDSetBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDIDDocument(dIDDocumentValue); + initialBuilder.setURI(uRIValue); + initialBuilder.setData(dataValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + DIDSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = dIDDocumentValue; + auto const actualOpt = rebuiltTx.getDIDDocument(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDIDDocument should be present"; + expectEqualField(expected, *actualOpt, "sfDIDDocument"); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = rebuiltTx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + } + + { + auto const& expected = dataValue; + auto const actualOpt = rebuiltTx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsDIDSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DIDSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsDIDSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DIDSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsDIDSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDIDSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + DIDSetBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDIDDocument()); + EXPECT_FALSE(tx.getDIDDocument().has_value()); + EXPECT_FALSE(tx.hasURI()); + EXPECT_FALSE(tx.getURI().has_value()); + EXPECT_FALSE(tx.hasData()); + EXPECT_FALSE(tx.getData().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/DelegateSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/DelegateSetTests.cpp new file mode 100644 index 0000000000..8e7fed9419 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/DelegateSetTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction DelegateSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsDelegateSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDelegateSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const authorizeValue = canonical_ACCOUNT(); + auto const permissionsValue = canonical_ARRAY(); + + DelegateSetBuilder builder{ + accountValue, + authorizeValue, + permissionsValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = authorizeValue; + auto const actual = tx.getAuthorize(); + expectEqualField(expected, actual, "sfAuthorize"); + } + + { + auto const& expected = permissionsValue; + auto const actual = tx.getPermissions(); + expectEqualField(expected, actual, "sfPermissions"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsDelegateSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDelegateSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const authorizeValue = canonical_ACCOUNT(); + auto const permissionsValue = canonical_ARRAY(); + + // Build an initial transaction + DelegateSetBuilder initialBuilder{ + accountValue, + authorizeValue, + permissionsValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + DelegateSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = authorizeValue; + auto const actual = rebuiltTx.getAuthorize(); + expectEqualField(expected, actual, "sfAuthorize"); + } + + { + auto const& expected = permissionsValue; + auto const actual = rebuiltTx.getPermissions(); + expectEqualField(expected, actual, "sfPermissions"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsDelegateSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DelegateSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsDelegateSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DelegateSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/DepositPreauthTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/DepositPreauthTests.cpp new file mode 100644 index 0000000000..36232eb220 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/DepositPreauthTests.cpp @@ -0,0 +1,240 @@ +// Auto-generated unit tests for transaction DepositPreauth + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsDepositPreauthTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDepositPreauth")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const authorizeValue = canonical_ACCOUNT(); + auto const unauthorizeValue = canonical_ACCOUNT(); + auto const authorizeCredentialsValue = canonical_ARRAY(); + auto const unauthorizeCredentialsValue = canonical_ARRAY(); + + DepositPreauthBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAuthorize(authorizeValue); + builder.setUnauthorize(unauthorizeValue); + builder.setAuthorizeCredentials(authorizeCredentialsValue); + builder.setUnauthorizeCredentials(unauthorizeCredentialsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = authorizeValue; + auto const actualOpt = tx.getAuthorize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAuthorize should be present"; + expectEqualField(expected, *actualOpt, "sfAuthorize"); + EXPECT_TRUE(tx.hasAuthorize()); + } + + { + auto const& expected = unauthorizeValue; + auto const actualOpt = tx.getUnauthorize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfUnauthorize should be present"; + expectEqualField(expected, *actualOpt, "sfUnauthorize"); + EXPECT_TRUE(tx.hasUnauthorize()); + } + + { + auto const& expected = authorizeCredentialsValue; + auto const actualOpt = tx.getAuthorizeCredentials(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAuthorizeCredentials should be present"; + expectEqualField(expected, *actualOpt, "sfAuthorizeCredentials"); + EXPECT_TRUE(tx.hasAuthorizeCredentials()); + } + + { + auto const& expected = unauthorizeCredentialsValue; + auto const actualOpt = tx.getUnauthorizeCredentials(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfUnauthorizeCredentials should be present"; + expectEqualField(expected, *actualOpt, "sfUnauthorizeCredentials"); + EXPECT_TRUE(tx.hasUnauthorizeCredentials()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsDepositPreauthTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDepositPreauthFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const authorizeValue = canonical_ACCOUNT(); + auto const unauthorizeValue = canonical_ACCOUNT(); + auto const authorizeCredentialsValue = canonical_ARRAY(); + auto const unauthorizeCredentialsValue = canonical_ARRAY(); + + // Build an initial transaction + DepositPreauthBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAuthorize(authorizeValue); + initialBuilder.setUnauthorize(unauthorizeValue); + initialBuilder.setAuthorizeCredentials(authorizeCredentialsValue); + initialBuilder.setUnauthorizeCredentials(unauthorizeCredentialsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + DepositPreauthBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = authorizeValue; + auto const actualOpt = rebuiltTx.getAuthorize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAuthorize should be present"; + expectEqualField(expected, *actualOpt, "sfAuthorize"); + } + + { + auto const& expected = unauthorizeValue; + auto const actualOpt = rebuiltTx.getUnauthorize(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfUnauthorize should be present"; + expectEqualField(expected, *actualOpt, "sfUnauthorize"); + } + + { + auto const& expected = authorizeCredentialsValue; + auto const actualOpt = rebuiltTx.getAuthorizeCredentials(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAuthorizeCredentials should be present"; + expectEqualField(expected, *actualOpt, "sfAuthorizeCredentials"); + } + + { + auto const& expected = unauthorizeCredentialsValue; + auto const actualOpt = rebuiltTx.getUnauthorizeCredentials(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfUnauthorizeCredentials should be present"; + expectEqualField(expected, *actualOpt, "sfUnauthorizeCredentials"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsDepositPreauthTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DepositPreauth{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsDepositPreauthTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(DepositPreauthBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsDepositPreauthTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testDepositPreauthNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + DepositPreauthBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAuthorize()); + EXPECT_FALSE(tx.getAuthorize().has_value()); + EXPECT_FALSE(tx.hasUnauthorize()); + EXPECT_FALSE(tx.getUnauthorize().has_value()); + EXPECT_FALSE(tx.hasAuthorizeCredentials()); + EXPECT_FALSE(tx.getAuthorizeCredentials().has_value()); + EXPECT_FALSE(tx.hasUnauthorizeCredentials()); + EXPECT_FALSE(tx.getUnauthorizeCredentials().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/EnableAmendmentTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/EnableAmendmentTests.cpp new file mode 100644 index 0000000000..e9dfe892e4 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/EnableAmendmentTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction EnableAmendment + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsEnableAmendmentTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEnableAmendment")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ledgerSequenceValue = canonical_UINT32(); + auto const amendmentValue = canonical_UINT256(); + + EnableAmendmentBuilder builder{ + accountValue, + ledgerSequenceValue, + amendmentValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ledgerSequenceValue; + auto const actual = tx.getLedgerSequence(); + expectEqualField(expected, actual, "sfLedgerSequence"); + } + + { + auto const& expected = amendmentValue; + auto const actual = tx.getAmendment(); + expectEqualField(expected, actual, "sfAmendment"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsEnableAmendmentTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEnableAmendmentFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ledgerSequenceValue = canonical_UINT32(); + auto const amendmentValue = canonical_UINT256(); + + // Build an initial transaction + EnableAmendmentBuilder initialBuilder{ + accountValue, + ledgerSequenceValue, + amendmentValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + EnableAmendmentBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ledgerSequenceValue; + auto const actual = rebuiltTx.getLedgerSequence(); + expectEqualField(expected, actual, "sfLedgerSequence"); + } + + { + auto const& expected = amendmentValue; + auto const actual = rebuiltTx.getAmendment(); + expectEqualField(expected, actual, "sfAmendment"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsEnableAmendmentTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EnableAmendment{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsEnableAmendmentTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EnableAmendmentBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/EscrowCancelTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/EscrowCancelTests.cpp new file mode 100644 index 0000000000..300a9b7615 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/EscrowCancelTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction EscrowCancel + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsEscrowCancelTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowCancel")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ownerValue = canonical_ACCOUNT(); + auto const offerSequenceValue = canonical_UINT32(); + + EscrowCancelBuilder builder{ + accountValue, + ownerValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ownerValue; + auto const actual = tx.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = offerSequenceValue; + auto const actual = tx.getOfferSequence(); + expectEqualField(expected, actual, "sfOfferSequence"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsEscrowCancelTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowCancelFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ownerValue = canonical_ACCOUNT(); + auto const offerSequenceValue = canonical_UINT32(); + + // Build an initial transaction + EscrowCancelBuilder initialBuilder{ + accountValue, + ownerValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + EscrowCancelBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ownerValue; + auto const actual = rebuiltTx.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = offerSequenceValue; + auto const actual = rebuiltTx.getOfferSequence(); + expectEqualField(expected, actual, "sfOfferSequence"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsEscrowCancelTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EscrowCancel{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsEscrowCancelTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EscrowCancelBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/EscrowCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/EscrowCreateTests.cpp new file mode 100644 index 0000000000..1f9b3d30a9 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/EscrowCreateTests.cpp @@ -0,0 +1,276 @@ +// Auto-generated unit tests for transaction EscrowCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsEscrowCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const conditionValue = canonical_VL(); + auto const cancelAfterValue = canonical_UINT32(); + auto const finishAfterValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + + EscrowCreateBuilder builder{ + accountValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setCondition(conditionValue); + builder.setCancelAfter(cancelAfterValue); + builder.setFinishAfter(finishAfterValue); + builder.setDestinationTag(destinationTagValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = conditionValue; + auto const actualOpt = tx.getCondition(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCondition should be present"; + expectEqualField(expected, *actualOpt, "sfCondition"); + EXPECT_TRUE(tx.hasCondition()); + } + + { + auto const& expected = cancelAfterValue; + auto const actualOpt = tx.getCancelAfter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCancelAfter should be present"; + expectEqualField(expected, *actualOpt, "sfCancelAfter"); + EXPECT_TRUE(tx.hasCancelAfter()); + } + + { + auto const& expected = finishAfterValue; + auto const actualOpt = tx.getFinishAfter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfFinishAfter should be present"; + expectEqualField(expected, *actualOpt, "sfFinishAfter"); + EXPECT_TRUE(tx.hasFinishAfter()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsEscrowCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const conditionValue = canonical_VL(); + auto const cancelAfterValue = canonical_UINT32(); + auto const finishAfterValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + + // Build an initial transaction + EscrowCreateBuilder initialBuilder{ + accountValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setCondition(conditionValue); + initialBuilder.setCancelAfter(cancelAfterValue); + initialBuilder.setFinishAfter(finishAfterValue); + initialBuilder.setDestinationTag(destinationTagValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + EscrowCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = conditionValue; + auto const actualOpt = rebuiltTx.getCondition(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCondition should be present"; + expectEqualField(expected, *actualOpt, "sfCondition"); + } + + { + auto const& expected = cancelAfterValue; + auto const actualOpt = rebuiltTx.getCancelAfter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCancelAfter should be present"; + expectEqualField(expected, *actualOpt, "sfCancelAfter"); + } + + { + auto const& expected = finishAfterValue; + auto const actualOpt = rebuiltTx.getFinishAfter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfFinishAfter should be present"; + expectEqualField(expected, *actualOpt, "sfFinishAfter"); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsEscrowCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EscrowCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsEscrowCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EscrowCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsEscrowCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + + EscrowCreateBuilder builder{ + accountValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasCondition()); + EXPECT_FALSE(tx.getCondition().has_value()); + EXPECT_FALSE(tx.hasCancelAfter()); + EXPECT_FALSE(tx.getCancelAfter().has_value()); + EXPECT_FALSE(tx.hasFinishAfter()); + EXPECT_FALSE(tx.getFinishAfter().has_value()); + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/EscrowFinishTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/EscrowFinishTests.cpp new file mode 100644 index 0000000000..f729d0fda3 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/EscrowFinishTests.cpp @@ -0,0 +1,255 @@ +// Auto-generated unit tests for transaction EscrowFinish + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsEscrowFinishTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowFinish")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ownerValue = canonical_ACCOUNT(); + auto const offerSequenceValue = canonical_UINT32(); + auto const fulfillmentValue = canonical_VL(); + auto const conditionValue = canonical_VL(); + auto const credentialIDsValue = canonical_VECTOR256(); + + EscrowFinishBuilder builder{ + accountValue, + ownerValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setFulfillment(fulfillmentValue); + builder.setCondition(conditionValue); + builder.setCredentialIDs(credentialIDsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ownerValue; + auto const actual = tx.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = offerSequenceValue; + auto const actual = tx.getOfferSequence(); + expectEqualField(expected, actual, "sfOfferSequence"); + } + + // Verify optional fields + { + auto const& expected = fulfillmentValue; + auto const actualOpt = tx.getFulfillment(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfFulfillment should be present"; + expectEqualField(expected, *actualOpt, "sfFulfillment"); + EXPECT_TRUE(tx.hasFulfillment()); + } + + { + auto const& expected = conditionValue; + auto const actualOpt = tx.getCondition(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCondition should be present"; + expectEqualField(expected, *actualOpt, "sfCondition"); + EXPECT_TRUE(tx.hasCondition()); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = tx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + EXPECT_TRUE(tx.hasCredentialIDs()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsEscrowFinishTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowFinishFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ownerValue = canonical_ACCOUNT(); + auto const offerSequenceValue = canonical_UINT32(); + auto const fulfillmentValue = canonical_VL(); + auto const conditionValue = canonical_VL(); + auto const credentialIDsValue = canonical_VECTOR256(); + + // Build an initial transaction + EscrowFinishBuilder initialBuilder{ + accountValue, + ownerValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + initialBuilder.setFulfillment(fulfillmentValue); + initialBuilder.setCondition(conditionValue); + initialBuilder.setCredentialIDs(credentialIDsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + EscrowFinishBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ownerValue; + auto const actual = rebuiltTx.getOwner(); + expectEqualField(expected, actual, "sfOwner"); + } + + { + auto const& expected = offerSequenceValue; + auto const actual = rebuiltTx.getOfferSequence(); + expectEqualField(expected, actual, "sfOfferSequence"); + } + + // Verify optional fields + { + auto const& expected = fulfillmentValue; + auto const actualOpt = rebuiltTx.getFulfillment(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfFulfillment should be present"; + expectEqualField(expected, *actualOpt, "sfFulfillment"); + } + + { + auto const& expected = conditionValue; + auto const actualOpt = rebuiltTx.getCondition(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCondition should be present"; + expectEqualField(expected, *actualOpt, "sfCondition"); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = rebuiltTx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsEscrowFinishTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EscrowFinish{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsEscrowFinishTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(EscrowFinishBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsEscrowFinishTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testEscrowFinishNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const ownerValue = canonical_ACCOUNT(); + auto const offerSequenceValue = canonical_UINT32(); + + EscrowFinishBuilder builder{ + accountValue, + ownerValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasFulfillment()); + EXPECT_FALSE(tx.getFulfillment().has_value()); + EXPECT_FALSE(tx.hasCondition()); + EXPECT_FALSE(tx.getCondition().has_value()); + EXPECT_FALSE(tx.hasCredentialIDs()); + EXPECT_FALSE(tx.getCredentialIDs().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LedgerStateFixTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LedgerStateFixTests.cpp new file mode 100644 index 0000000000..b366605a4f --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LedgerStateFixTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction LedgerStateFix + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLedgerStateFixTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLedgerStateFix")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ledgerFixTypeValue = canonical_UINT16(); + auto const ownerValue = canonical_ACCOUNT(); + + LedgerStateFixBuilder builder{ + accountValue, + ledgerFixTypeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setOwner(ownerValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ledgerFixTypeValue; + auto const actual = tx.getLedgerFixType(); + expectEqualField(expected, actual, "sfLedgerFixType"); + } + + // Verify optional fields + { + auto const& expected = ownerValue; + auto const actualOpt = tx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + EXPECT_TRUE(tx.hasOwner()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLedgerStateFixTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLedgerStateFixFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ledgerFixTypeValue = canonical_UINT16(); + auto const ownerValue = canonical_ACCOUNT(); + + // Build an initial transaction + LedgerStateFixBuilder initialBuilder{ + accountValue, + ledgerFixTypeValue, + sequenceValue, + feeValue + }; + + initialBuilder.setOwner(ownerValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LedgerStateFixBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ledgerFixTypeValue; + auto const actual = rebuiltTx.getLedgerFixType(); + expectEqualField(expected, actual, "sfLedgerFixType"); + } + + // Verify optional fields + { + auto const& expected = ownerValue; + auto const actualOpt = rebuiltTx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLedgerStateFixTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LedgerStateFix{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLedgerStateFixTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LedgerStateFixBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsLedgerStateFixTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLedgerStateFixNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const ledgerFixTypeValue = canonical_UINT16(); + + LedgerStateFixBuilder builder{ + accountValue, + ledgerFixTypeValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasOwner()); + EXPECT_FALSE(tx.getOwner().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverClawbackTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverClawbackTests.cpp new file mode 100644 index 0000000000..1e6c72f458 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverClawbackTests.cpp @@ -0,0 +1,198 @@ +// Auto-generated unit tests for transaction LoanBrokerCoverClawback + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanBrokerCoverClawbackTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverClawback")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + LoanBrokerCoverClawbackBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setLoanBrokerID(loanBrokerIDValue); + builder.setAmount(amountValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = loanBrokerIDValue; + auto const actualOpt = tx.getLoanBrokerID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanBrokerID should be present"; + expectEqualField(expected, *actualOpt, "sfLoanBrokerID"); + EXPECT_TRUE(tx.hasLoanBrokerID()); + } + + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanBrokerCoverClawbackTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverClawbackFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + LoanBrokerCoverClawbackBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setLoanBrokerID(loanBrokerIDValue); + initialBuilder.setAmount(amountValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanBrokerCoverClawbackBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = loanBrokerIDValue; + auto const actualOpt = rebuiltTx.getLoanBrokerID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanBrokerID should be present"; + expectEqualField(expected, *actualOpt, "sfLoanBrokerID"); + } + + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerCoverClawbackTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerCoverClawback{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerCoverClawbackTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerCoverClawbackBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsLoanBrokerCoverClawbackTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverClawbackNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + LoanBrokerCoverClawbackBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasLoanBrokerID()); + EXPECT_FALSE(tx.getLoanBrokerID().has_value()); + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverDepositTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverDepositTests.cpp new file mode 100644 index 0000000000..d6addb2fef --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverDepositTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction LoanBrokerCoverDeposit + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanBrokerCoverDepositTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverDeposit")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + LoanBrokerCoverDepositBuilder builder{ + accountValue, + loanBrokerIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = tx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanBrokerCoverDepositTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverDepositFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + LoanBrokerCoverDepositBuilder initialBuilder{ + accountValue, + loanBrokerIDValue, + amountValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanBrokerCoverDepositBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = rebuiltTx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerCoverDepositTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerCoverDeposit{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerCoverDepositTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerCoverDepositBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverWithdrawTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverWithdrawTests.cpp new file mode 100644 index 0000000000..3e66944e39 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerCoverWithdrawTests.cpp @@ -0,0 +1,234 @@ +// Auto-generated unit tests for transaction LoanBrokerCoverWithdraw + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanBrokerCoverWithdrawTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverWithdraw")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + + LoanBrokerCoverWithdrawBuilder builder{ + accountValue, + loanBrokerIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDestination(destinationValue); + builder.setDestinationTag(destinationTagValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = tx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = tx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + EXPECT_TRUE(tx.hasDestination()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanBrokerCoverWithdrawTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverWithdrawFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + + // Build an initial transaction + LoanBrokerCoverWithdrawBuilder initialBuilder{ + accountValue, + loanBrokerIDValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDestination(destinationValue); + initialBuilder.setDestinationTag(destinationTagValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanBrokerCoverWithdrawBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = rebuiltTx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = rebuiltTx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerCoverWithdrawTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerCoverWithdraw{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerCoverWithdrawTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerCoverWithdrawBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsLoanBrokerCoverWithdrawTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerCoverWithdrawNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + LoanBrokerCoverWithdrawBuilder builder{ + accountValue, + loanBrokerIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDestination()); + EXPECT_FALSE(tx.getDestination().has_value()); + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerDeleteTests.cpp new file mode 100644 index 0000000000..b557ab4397 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerDeleteTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction LoanBrokerDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanBrokerDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + + LoanBrokerDeleteBuilder builder{ + accountValue, + loanBrokerIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = tx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanBrokerDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + + // Build an initial transaction + LoanBrokerDeleteBuilder initialBuilder{ + accountValue, + loanBrokerIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanBrokerDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = rebuiltTx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerSetTests.cpp new file mode 100644 index 0000000000..e270332f42 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanBrokerSetTests.cpp @@ -0,0 +1,300 @@ +// Auto-generated unit tests for transaction LoanBrokerSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanBrokerSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const loanBrokerIDValue = canonical_UINT256(); + auto const dataValue = canonical_VL(); + auto const managementFeeRateValue = canonical_UINT16(); + auto const debtMaximumValue = canonical_NUMBER(); + auto const coverRateMinimumValue = canonical_UINT32(); + auto const coverRateLiquidationValue = canonical_UINT32(); + + LoanBrokerSetBuilder builder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setLoanBrokerID(loanBrokerIDValue); + builder.setData(dataValue); + builder.setManagementFeeRate(managementFeeRateValue); + builder.setDebtMaximum(debtMaximumValue); + builder.setCoverRateMinimum(coverRateMinimumValue); + builder.setCoverRateLiquidation(coverRateLiquidationValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = tx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + // Verify optional fields + { + auto const& expected = loanBrokerIDValue; + auto const actualOpt = tx.getLoanBrokerID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanBrokerID should be present"; + expectEqualField(expected, *actualOpt, "sfLoanBrokerID"); + EXPECT_TRUE(tx.hasLoanBrokerID()); + } + + { + auto const& expected = dataValue; + auto const actualOpt = tx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(tx.hasData()); + } + + { + auto const& expected = managementFeeRateValue; + auto const actualOpt = tx.getManagementFeeRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfManagementFeeRate should be present"; + expectEqualField(expected, *actualOpt, "sfManagementFeeRate"); + EXPECT_TRUE(tx.hasManagementFeeRate()); + } + + { + auto const& expected = debtMaximumValue; + auto const actualOpt = tx.getDebtMaximum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDebtMaximum should be present"; + expectEqualField(expected, *actualOpt, "sfDebtMaximum"); + EXPECT_TRUE(tx.hasDebtMaximum()); + } + + { + auto const& expected = coverRateMinimumValue; + auto const actualOpt = tx.getCoverRateMinimum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCoverRateMinimum should be present"; + expectEqualField(expected, *actualOpt, "sfCoverRateMinimum"); + EXPECT_TRUE(tx.hasCoverRateMinimum()); + } + + { + auto const& expected = coverRateLiquidationValue; + auto const actualOpt = tx.getCoverRateLiquidation(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCoverRateLiquidation should be present"; + expectEqualField(expected, *actualOpt, "sfCoverRateLiquidation"); + EXPECT_TRUE(tx.hasCoverRateLiquidation()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanBrokerSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const loanBrokerIDValue = canonical_UINT256(); + auto const dataValue = canonical_VL(); + auto const managementFeeRateValue = canonical_UINT16(); + auto const debtMaximumValue = canonical_NUMBER(); + auto const coverRateMinimumValue = canonical_UINT32(); + auto const coverRateLiquidationValue = canonical_UINT32(); + + // Build an initial transaction + LoanBrokerSetBuilder initialBuilder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setLoanBrokerID(loanBrokerIDValue); + initialBuilder.setData(dataValue); + initialBuilder.setManagementFeeRate(managementFeeRateValue); + initialBuilder.setDebtMaximum(debtMaximumValue); + initialBuilder.setCoverRateMinimum(coverRateMinimumValue); + initialBuilder.setCoverRateLiquidation(coverRateLiquidationValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanBrokerSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = rebuiltTx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + // Verify optional fields + { + auto const& expected = loanBrokerIDValue; + auto const actualOpt = rebuiltTx.getLoanBrokerID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanBrokerID should be present"; + expectEqualField(expected, *actualOpt, "sfLoanBrokerID"); + } + + { + auto const& expected = dataValue; + auto const actualOpt = rebuiltTx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + } + + { + auto const& expected = managementFeeRateValue; + auto const actualOpt = rebuiltTx.getManagementFeeRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfManagementFeeRate should be present"; + expectEqualField(expected, *actualOpt, "sfManagementFeeRate"); + } + + { + auto const& expected = debtMaximumValue; + auto const actualOpt = rebuiltTx.getDebtMaximum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDebtMaximum should be present"; + expectEqualField(expected, *actualOpt, "sfDebtMaximum"); + } + + { + auto const& expected = coverRateMinimumValue; + auto const actualOpt = rebuiltTx.getCoverRateMinimum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCoverRateMinimum should be present"; + expectEqualField(expected, *actualOpt, "sfCoverRateMinimum"); + } + + { + auto const& expected = coverRateLiquidationValue; + auto const actualOpt = rebuiltTx.getCoverRateLiquidation(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCoverRateLiquidation should be present"; + expectEqualField(expected, *actualOpt, "sfCoverRateLiquidation"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanBrokerSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanBrokerSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsLoanBrokerSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanBrokerSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const vaultIDValue = canonical_UINT256(); + + LoanBrokerSetBuilder builder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasLoanBrokerID()); + EXPECT_FALSE(tx.getLoanBrokerID().has_value()); + EXPECT_FALSE(tx.hasData()); + EXPECT_FALSE(tx.getData().has_value()); + EXPECT_FALSE(tx.hasManagementFeeRate()); + EXPECT_FALSE(tx.getManagementFeeRate().has_value()); + EXPECT_FALSE(tx.hasDebtMaximum()); + EXPECT_FALSE(tx.getDebtMaximum().has_value()); + EXPECT_FALSE(tx.hasCoverRateMinimum()); + EXPECT_FALSE(tx.getCoverRateMinimum().has_value()); + EXPECT_FALSE(tx.hasCoverRateLiquidation()); + EXPECT_FALSE(tx.getCoverRateLiquidation().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanDeleteTests.cpp new file mode 100644 index 0000000000..0edcdf4d06 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanDeleteTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction LoanDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanIDValue = canonical_UINT256(); + + LoanDeleteBuilder builder{ + accountValue, + loanIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanIDValue; + auto const actual = tx.getLoanID(); + expectEqualField(expected, actual, "sfLoanID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanIDValue = canonical_UINT256(); + + // Build an initial transaction + LoanDeleteBuilder initialBuilder{ + accountValue, + loanIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanIDValue; + auto const actual = rebuiltTx.getLoanID(); + expectEqualField(expected, actual, "sfLoanID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanManageTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanManageTests.cpp new file mode 100644 index 0000000000..bb842330d6 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanManageTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction LoanManage + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanManageTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanManage")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanIDValue = canonical_UINT256(); + + LoanManageBuilder builder{ + accountValue, + loanIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanIDValue; + auto const actual = tx.getLoanID(); + expectEqualField(expected, actual, "sfLoanID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanManageTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanManageFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanIDValue = canonical_UINT256(); + + // Build an initial transaction + LoanManageBuilder initialBuilder{ + accountValue, + loanIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanManageBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanIDValue; + auto const actual = rebuiltTx.getLoanID(); + expectEqualField(expected, actual, "sfLoanID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanManageTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanManage{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanManageTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanManageBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanPayTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanPayTests.cpp new file mode 100644 index 0000000000..2b0f16f25c --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanPayTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction LoanPay + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanPayTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanPay")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + LoanPayBuilder builder{ + accountValue, + loanIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanIDValue; + auto const actual = tx.getLoanID(); + expectEqualField(expected, actual, "sfLoanID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanPayTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanPayFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + LoanPayBuilder initialBuilder{ + accountValue, + loanIDValue, + amountValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanPayBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanIDValue; + auto const actual = rebuiltTx.getLoanID(); + expectEqualField(expected, actual, "sfLoanID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanPayTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanPay{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanPayTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanPayBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanSetTests.cpp new file mode 100644 index 0000000000..4141a958a0 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanSetTests.cpp @@ -0,0 +1,507 @@ +// Auto-generated unit tests for transaction LoanSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsLoanSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const dataValue = canonical_VL(); + auto const counterpartyValue = canonical_ACCOUNT(); + auto const counterpartySignatureValue = canonical_OBJECT(); + auto const loanOriginationFeeValue = canonical_NUMBER(); + auto const loanServiceFeeValue = canonical_NUMBER(); + auto const latePaymentFeeValue = canonical_NUMBER(); + auto const closePaymentFeeValue = canonical_NUMBER(); + auto const overpaymentFeeValue = canonical_UINT32(); + auto const interestRateValue = canonical_UINT32(); + auto const lateInterestRateValue = canonical_UINT32(); + auto const closeInterestRateValue = canonical_UINT32(); + auto const overpaymentInterestRateValue = canonical_UINT32(); + auto const principalRequestedValue = canonical_NUMBER(); + auto const paymentTotalValue = canonical_UINT32(); + auto const paymentIntervalValue = canonical_UINT32(); + auto const gracePeriodValue = canonical_UINT32(); + + LoanSetBuilder builder{ + accountValue, + loanBrokerIDValue, + principalRequestedValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setData(dataValue); + builder.setCounterparty(counterpartyValue); + builder.setCounterpartySignature(counterpartySignatureValue); + builder.setLoanOriginationFee(loanOriginationFeeValue); + builder.setLoanServiceFee(loanServiceFeeValue); + builder.setLatePaymentFee(latePaymentFeeValue); + builder.setClosePaymentFee(closePaymentFeeValue); + builder.setOverpaymentFee(overpaymentFeeValue); + builder.setInterestRate(interestRateValue); + builder.setLateInterestRate(lateInterestRateValue); + builder.setCloseInterestRate(closeInterestRateValue); + builder.setOverpaymentInterestRate(overpaymentInterestRateValue); + builder.setPaymentTotal(paymentTotalValue); + builder.setPaymentInterval(paymentIntervalValue); + builder.setGracePeriod(gracePeriodValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = tx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = principalRequestedValue; + auto const actual = tx.getPrincipalRequested(); + expectEqualField(expected, actual, "sfPrincipalRequested"); + } + + // Verify optional fields + { + auto const& expected = dataValue; + auto const actualOpt = tx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(tx.hasData()); + } + + { + auto const& expected = counterpartyValue; + auto const actualOpt = tx.getCounterparty(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCounterparty should be present"; + expectEqualField(expected, *actualOpt, "sfCounterparty"); + EXPECT_TRUE(tx.hasCounterparty()); + } + + { + auto const& expected = counterpartySignatureValue; + auto const actualOpt = tx.getCounterpartySignature(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCounterpartySignature should be present"; + expectEqualField(expected, *actualOpt, "sfCounterpartySignature"); + EXPECT_TRUE(tx.hasCounterpartySignature()); + } + + { + auto const& expected = loanOriginationFeeValue; + auto const actualOpt = tx.getLoanOriginationFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanOriginationFee should be present"; + expectEqualField(expected, *actualOpt, "sfLoanOriginationFee"); + EXPECT_TRUE(tx.hasLoanOriginationFee()); + } + + { + auto const& expected = loanServiceFeeValue; + auto const actualOpt = tx.getLoanServiceFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanServiceFee should be present"; + expectEqualField(expected, *actualOpt, "sfLoanServiceFee"); + EXPECT_TRUE(tx.hasLoanServiceFee()); + } + + { + auto const& expected = latePaymentFeeValue; + auto const actualOpt = tx.getLatePaymentFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLatePaymentFee should be present"; + expectEqualField(expected, *actualOpt, "sfLatePaymentFee"); + EXPECT_TRUE(tx.hasLatePaymentFee()); + } + + { + auto const& expected = closePaymentFeeValue; + auto const actualOpt = tx.getClosePaymentFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfClosePaymentFee should be present"; + expectEqualField(expected, *actualOpt, "sfClosePaymentFee"); + EXPECT_TRUE(tx.hasClosePaymentFee()); + } + + { + auto const& expected = overpaymentFeeValue; + auto const actualOpt = tx.getOverpaymentFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOverpaymentFee should be present"; + expectEqualField(expected, *actualOpt, "sfOverpaymentFee"); + EXPECT_TRUE(tx.hasOverpaymentFee()); + } + + { + auto const& expected = interestRateValue; + auto const actualOpt = tx.getInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfInterestRate"); + EXPECT_TRUE(tx.hasInterestRate()); + } + + { + auto const& expected = lateInterestRateValue; + auto const actualOpt = tx.getLateInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLateInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfLateInterestRate"); + EXPECT_TRUE(tx.hasLateInterestRate()); + } + + { + auto const& expected = closeInterestRateValue; + auto const actualOpt = tx.getCloseInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCloseInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfCloseInterestRate"); + EXPECT_TRUE(tx.hasCloseInterestRate()); + } + + { + auto const& expected = overpaymentInterestRateValue; + auto const actualOpt = tx.getOverpaymentInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOverpaymentInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfOverpaymentInterestRate"); + EXPECT_TRUE(tx.hasOverpaymentInterestRate()); + } + + { + auto const& expected = paymentTotalValue; + auto const actualOpt = tx.getPaymentTotal(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPaymentTotal should be present"; + expectEqualField(expected, *actualOpt, "sfPaymentTotal"); + EXPECT_TRUE(tx.hasPaymentTotal()); + } + + { + auto const& expected = paymentIntervalValue; + auto const actualOpt = tx.getPaymentInterval(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPaymentInterval should be present"; + expectEqualField(expected, *actualOpt, "sfPaymentInterval"); + EXPECT_TRUE(tx.hasPaymentInterval()); + } + + { + auto const& expected = gracePeriodValue; + auto const actualOpt = tx.getGracePeriod(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfGracePeriod should be present"; + expectEqualField(expected, *actualOpt, "sfGracePeriod"); + EXPECT_TRUE(tx.hasGracePeriod()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsLoanSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const dataValue = canonical_VL(); + auto const counterpartyValue = canonical_ACCOUNT(); + auto const counterpartySignatureValue = canonical_OBJECT(); + auto const loanOriginationFeeValue = canonical_NUMBER(); + auto const loanServiceFeeValue = canonical_NUMBER(); + auto const latePaymentFeeValue = canonical_NUMBER(); + auto const closePaymentFeeValue = canonical_NUMBER(); + auto const overpaymentFeeValue = canonical_UINT32(); + auto const interestRateValue = canonical_UINT32(); + auto const lateInterestRateValue = canonical_UINT32(); + auto const closeInterestRateValue = canonical_UINT32(); + auto const overpaymentInterestRateValue = canonical_UINT32(); + auto const principalRequestedValue = canonical_NUMBER(); + auto const paymentTotalValue = canonical_UINT32(); + auto const paymentIntervalValue = canonical_UINT32(); + auto const gracePeriodValue = canonical_UINT32(); + + // Build an initial transaction + LoanSetBuilder initialBuilder{ + accountValue, + loanBrokerIDValue, + principalRequestedValue, + sequenceValue, + feeValue + }; + + initialBuilder.setData(dataValue); + initialBuilder.setCounterparty(counterpartyValue); + initialBuilder.setCounterpartySignature(counterpartySignatureValue); + initialBuilder.setLoanOriginationFee(loanOriginationFeeValue); + initialBuilder.setLoanServiceFee(loanServiceFeeValue); + initialBuilder.setLatePaymentFee(latePaymentFeeValue); + initialBuilder.setClosePaymentFee(closePaymentFeeValue); + initialBuilder.setOverpaymentFee(overpaymentFeeValue); + initialBuilder.setInterestRate(interestRateValue); + initialBuilder.setLateInterestRate(lateInterestRateValue); + initialBuilder.setCloseInterestRate(closeInterestRateValue); + initialBuilder.setOverpaymentInterestRate(overpaymentInterestRateValue); + initialBuilder.setPaymentTotal(paymentTotalValue); + initialBuilder.setPaymentInterval(paymentIntervalValue); + initialBuilder.setGracePeriod(gracePeriodValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = loanBrokerIDValue; + auto const actual = rebuiltTx.getLoanBrokerID(); + expectEqualField(expected, actual, "sfLoanBrokerID"); + } + + { + auto const& expected = principalRequestedValue; + auto const actual = rebuiltTx.getPrincipalRequested(); + expectEqualField(expected, actual, "sfPrincipalRequested"); + } + + // Verify optional fields + { + auto const& expected = dataValue; + auto const actualOpt = rebuiltTx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + } + + { + auto const& expected = counterpartyValue; + auto const actualOpt = rebuiltTx.getCounterparty(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCounterparty should be present"; + expectEqualField(expected, *actualOpt, "sfCounterparty"); + } + + { + auto const& expected = counterpartySignatureValue; + auto const actualOpt = rebuiltTx.getCounterpartySignature(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCounterpartySignature should be present"; + expectEqualField(expected, *actualOpt, "sfCounterpartySignature"); + } + + { + auto const& expected = loanOriginationFeeValue; + auto const actualOpt = rebuiltTx.getLoanOriginationFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanOriginationFee should be present"; + expectEqualField(expected, *actualOpt, "sfLoanOriginationFee"); + } + + { + auto const& expected = loanServiceFeeValue; + auto const actualOpt = rebuiltTx.getLoanServiceFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLoanServiceFee should be present"; + expectEqualField(expected, *actualOpt, "sfLoanServiceFee"); + } + + { + auto const& expected = latePaymentFeeValue; + auto const actualOpt = rebuiltTx.getLatePaymentFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLatePaymentFee should be present"; + expectEqualField(expected, *actualOpt, "sfLatePaymentFee"); + } + + { + auto const& expected = closePaymentFeeValue; + auto const actualOpt = rebuiltTx.getClosePaymentFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfClosePaymentFee should be present"; + expectEqualField(expected, *actualOpt, "sfClosePaymentFee"); + } + + { + auto const& expected = overpaymentFeeValue; + auto const actualOpt = rebuiltTx.getOverpaymentFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOverpaymentFee should be present"; + expectEqualField(expected, *actualOpt, "sfOverpaymentFee"); + } + + { + auto const& expected = interestRateValue; + auto const actualOpt = rebuiltTx.getInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfInterestRate"); + } + + { + auto const& expected = lateInterestRateValue; + auto const actualOpt = rebuiltTx.getLateInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLateInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfLateInterestRate"); + } + + { + auto const& expected = closeInterestRateValue; + auto const actualOpt = rebuiltTx.getCloseInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCloseInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfCloseInterestRate"); + } + + { + auto const& expected = overpaymentInterestRateValue; + auto const actualOpt = rebuiltTx.getOverpaymentInterestRate(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOverpaymentInterestRate should be present"; + expectEqualField(expected, *actualOpt, "sfOverpaymentInterestRate"); + } + + { + auto const& expected = paymentTotalValue; + auto const actualOpt = rebuiltTx.getPaymentTotal(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPaymentTotal should be present"; + expectEqualField(expected, *actualOpt, "sfPaymentTotal"); + } + + { + auto const& expected = paymentIntervalValue; + auto const actualOpt = rebuiltTx.getPaymentInterval(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPaymentInterval should be present"; + expectEqualField(expected, *actualOpt, "sfPaymentInterval"); + } + + { + auto const& expected = gracePeriodValue; + auto const actualOpt = rebuiltTx.getGracePeriod(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfGracePeriod should be present"; + expectEqualField(expected, *actualOpt, "sfGracePeriod"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsLoanSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(LoanSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsLoanSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testLoanSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const loanBrokerIDValue = canonical_UINT256(); + auto const principalRequestedValue = canonical_NUMBER(); + + LoanSetBuilder builder{ + accountValue, + loanBrokerIDValue, + principalRequestedValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasData()); + EXPECT_FALSE(tx.getData().has_value()); + EXPECT_FALSE(tx.hasCounterparty()); + EXPECT_FALSE(tx.getCounterparty().has_value()); + EXPECT_FALSE(tx.hasCounterpartySignature()); + EXPECT_FALSE(tx.getCounterpartySignature().has_value()); + EXPECT_FALSE(tx.hasLoanOriginationFee()); + EXPECT_FALSE(tx.getLoanOriginationFee().has_value()); + EXPECT_FALSE(tx.hasLoanServiceFee()); + EXPECT_FALSE(tx.getLoanServiceFee().has_value()); + EXPECT_FALSE(tx.hasLatePaymentFee()); + EXPECT_FALSE(tx.getLatePaymentFee().has_value()); + EXPECT_FALSE(tx.hasClosePaymentFee()); + EXPECT_FALSE(tx.getClosePaymentFee().has_value()); + EXPECT_FALSE(tx.hasOverpaymentFee()); + EXPECT_FALSE(tx.getOverpaymentFee().has_value()); + EXPECT_FALSE(tx.hasInterestRate()); + EXPECT_FALSE(tx.getInterestRate().has_value()); + EXPECT_FALSE(tx.hasLateInterestRate()); + EXPECT_FALSE(tx.getLateInterestRate().has_value()); + EXPECT_FALSE(tx.hasCloseInterestRate()); + EXPECT_FALSE(tx.getCloseInterestRate().has_value()); + EXPECT_FALSE(tx.hasOverpaymentInterestRate()); + EXPECT_FALSE(tx.getOverpaymentInterestRate().has_value()); + EXPECT_FALSE(tx.hasPaymentTotal()); + EXPECT_FALSE(tx.getPaymentTotal().has_value()); + EXPECT_FALSE(tx.hasPaymentInterval()); + EXPECT_FALSE(tx.getPaymentInterval().has_value()); + EXPECT_FALSE(tx.hasGracePeriod()); + EXPECT_FALSE(tx.getGracePeriod().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/MPTokenAuthorizeTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenAuthorizeTests.cpp new file mode 100644 index 0000000000..bde6df05ff --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenAuthorizeTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction MPTokenAuthorize + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsMPTokenAuthorizeTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenAuthorize")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const holderValue = canonical_ACCOUNT(); + + MPTokenAuthorizeBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setHolder(holderValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = tx.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + // Verify optional fields + { + auto const& expected = holderValue; + auto const actualOpt = tx.getHolder(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfHolder should be present"; + expectEqualField(expected, *actualOpt, "sfHolder"); + EXPECT_TRUE(tx.hasHolder()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsMPTokenAuthorizeTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenAuthorizeFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const holderValue = canonical_ACCOUNT(); + + // Build an initial transaction + MPTokenAuthorizeBuilder initialBuilder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setHolder(holderValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + MPTokenAuthorizeBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = rebuiltTx.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + // Verify optional fields + { + auto const& expected = holderValue; + auto const actualOpt = rebuiltTx.getHolder(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfHolder should be present"; + expectEqualField(expected, *actualOpt, "sfHolder"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenAuthorizeTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenAuthorize{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenAuthorizeTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenAuthorizeBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsMPTokenAuthorizeTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenAuthorizeNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + + MPTokenAuthorizeBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasHolder()); + EXPECT_FALSE(tx.getHolder().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceCreateTests.cpp new file mode 100644 index 0000000000..dd4874e268 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceCreateTests.cpp @@ -0,0 +1,282 @@ +// Auto-generated unit tests for transaction MPTokenIssuanceCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsMPTokenIssuanceCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetScaleValue = canonical_UINT8(); + auto const transferFeeValue = canonical_UINT16(); + auto const maximumAmountValue = canonical_UINT64(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const domainIDValue = canonical_UINT256(); + auto const mutableFlagsValue = canonical_UINT32(); + + MPTokenIssuanceCreateBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAssetScale(assetScaleValue); + builder.setTransferFee(transferFeeValue); + builder.setMaximumAmount(maximumAmountValue); + builder.setMPTokenMetadata(mPTokenMetadataValue); + builder.setDomainID(domainIDValue); + builder.setMutableFlags(mutableFlagsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = assetScaleValue; + auto const actualOpt = tx.getAssetScale(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetScale should be present"; + expectEqualField(expected, *actualOpt, "sfAssetScale"); + EXPECT_TRUE(tx.hasAssetScale()); + } + + { + auto const& expected = transferFeeValue; + auto const actualOpt = tx.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferFee should be present"; + expectEqualField(expected, *actualOpt, "sfTransferFee"); + EXPECT_TRUE(tx.hasTransferFee()); + } + + { + auto const& expected = maximumAmountValue; + auto const actualOpt = tx.getMaximumAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMaximumAmount should be present"; + expectEqualField(expected, *actualOpt, "sfMaximumAmount"); + EXPECT_TRUE(tx.hasMaximumAmount()); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = tx.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMPTokenMetadata should be present"; + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + EXPECT_TRUE(tx.hasMPTokenMetadata()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + + { + auto const& expected = mutableFlagsValue; + auto const actualOpt = tx.getMutableFlags(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMutableFlags should be present"; + expectEqualField(expected, *actualOpt, "sfMutableFlags"); + EXPECT_TRUE(tx.hasMutableFlags()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsMPTokenIssuanceCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetScaleValue = canonical_UINT8(); + auto const transferFeeValue = canonical_UINT16(); + auto const maximumAmountValue = canonical_UINT64(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const domainIDValue = canonical_UINT256(); + auto const mutableFlagsValue = canonical_UINT32(); + + // Build an initial transaction + MPTokenIssuanceCreateBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAssetScale(assetScaleValue); + initialBuilder.setTransferFee(transferFeeValue); + initialBuilder.setMaximumAmount(maximumAmountValue); + initialBuilder.setMPTokenMetadata(mPTokenMetadataValue); + initialBuilder.setDomainID(domainIDValue); + initialBuilder.setMutableFlags(mutableFlagsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + MPTokenIssuanceCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = assetScaleValue; + auto const actualOpt = rebuiltTx.getAssetScale(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetScale should be present"; + expectEqualField(expected, *actualOpt, "sfAssetScale"); + } + + { + auto const& expected = transferFeeValue; + auto const actualOpt = rebuiltTx.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferFee should be present"; + expectEqualField(expected, *actualOpt, "sfTransferFee"); + } + + { + auto const& expected = maximumAmountValue; + auto const actualOpt = rebuiltTx.getMaximumAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMaximumAmount should be present"; + expectEqualField(expected, *actualOpt, "sfMaximumAmount"); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = rebuiltTx.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMPTokenMetadata should be present"; + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + + { + auto const& expected = mutableFlagsValue; + auto const actualOpt = rebuiltTx.getMutableFlags(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMutableFlags should be present"; + expectEqualField(expected, *actualOpt, "sfMutableFlags"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenIssuanceCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenIssuanceCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenIssuanceCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenIssuanceCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsMPTokenIssuanceCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + MPTokenIssuanceCreateBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAssetScale()); + EXPECT_FALSE(tx.getAssetScale().has_value()); + EXPECT_FALSE(tx.hasTransferFee()); + EXPECT_FALSE(tx.getTransferFee().has_value()); + EXPECT_FALSE(tx.hasMaximumAmount()); + EXPECT_FALSE(tx.getMaximumAmount().has_value()); + EXPECT_FALSE(tx.hasMPTokenMetadata()); + EXPECT_FALSE(tx.getMPTokenMetadata().has_value()); + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); + EXPECT_FALSE(tx.hasMutableFlags()); + EXPECT_FALSE(tx.getMutableFlags().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceDestroyTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceDestroyTests.cpp new file mode 100644 index 0000000000..8a69c1f63a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceDestroyTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction MPTokenIssuanceDestroy + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsMPTokenIssuanceDestroyTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceDestroy")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + + MPTokenIssuanceDestroyBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = tx.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsMPTokenIssuanceDestroyTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceDestroyFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + + // Build an initial transaction + MPTokenIssuanceDestroyBuilder initialBuilder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + MPTokenIssuanceDestroyBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = rebuiltTx.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenIssuanceDestroyTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenIssuanceDestroy{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenIssuanceDestroyTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenIssuanceDestroyBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceSetTests.cpp new file mode 100644 index 0000000000..2ed9e42184 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/MPTokenIssuanceSetTests.cpp @@ -0,0 +1,279 @@ +// Auto-generated unit tests for transaction MPTokenIssuanceSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsMPTokenIssuanceSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const holderValue = canonical_ACCOUNT(); + auto const domainIDValue = canonical_UINT256(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const transferFeeValue = canonical_UINT16(); + auto const mutableFlagsValue = canonical_UINT32(); + + MPTokenIssuanceSetBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setHolder(holderValue); + builder.setDomainID(domainIDValue); + builder.setMPTokenMetadata(mPTokenMetadataValue); + builder.setTransferFee(transferFeeValue); + builder.setMutableFlags(mutableFlagsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = tx.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + // Verify optional fields + { + auto const& expected = holderValue; + auto const actualOpt = tx.getHolder(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfHolder should be present"; + expectEqualField(expected, *actualOpt, "sfHolder"); + EXPECT_TRUE(tx.hasHolder()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = tx.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMPTokenMetadata should be present"; + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + EXPECT_TRUE(tx.hasMPTokenMetadata()); + } + + { + auto const& expected = transferFeeValue; + auto const actualOpt = tx.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferFee should be present"; + expectEqualField(expected, *actualOpt, "sfTransferFee"); + EXPECT_TRUE(tx.hasTransferFee()); + } + + { + auto const& expected = mutableFlagsValue; + auto const actualOpt = tx.getMutableFlags(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMutableFlags should be present"; + expectEqualField(expected, *actualOpt, "sfMutableFlags"); + EXPECT_TRUE(tx.hasMutableFlags()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsMPTokenIssuanceSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + auto const holderValue = canonical_ACCOUNT(); + auto const domainIDValue = canonical_UINT256(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const transferFeeValue = canonical_UINT16(); + auto const mutableFlagsValue = canonical_UINT32(); + + // Build an initial transaction + MPTokenIssuanceSetBuilder initialBuilder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setHolder(holderValue); + initialBuilder.setDomainID(domainIDValue); + initialBuilder.setMPTokenMetadata(mPTokenMetadataValue); + initialBuilder.setTransferFee(transferFeeValue); + initialBuilder.setMutableFlags(mutableFlagsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + MPTokenIssuanceSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = mPTokenIssuanceIDValue; + auto const actual = rebuiltTx.getMPTokenIssuanceID(); + expectEqualField(expected, actual, "sfMPTokenIssuanceID"); + } + + // Verify optional fields + { + auto const& expected = holderValue; + auto const actualOpt = rebuiltTx.getHolder(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfHolder should be present"; + expectEqualField(expected, *actualOpt, "sfHolder"); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = rebuiltTx.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMPTokenMetadata should be present"; + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + } + + { + auto const& expected = transferFeeValue; + auto const actualOpt = rebuiltTx.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferFee should be present"; + expectEqualField(expected, *actualOpt, "sfTransferFee"); + } + + { + auto const& expected = mutableFlagsValue; + auto const actualOpt = rebuiltTx.getMutableFlags(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMutableFlags should be present"; + expectEqualField(expected, *actualOpt, "sfMutableFlags"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenIssuanceSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenIssuanceSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsMPTokenIssuanceSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(MPTokenIssuanceSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsMPTokenIssuanceSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testMPTokenIssuanceSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const mPTokenIssuanceIDValue = canonical_UINT192(); + + MPTokenIssuanceSetBuilder builder{ + accountValue, + mPTokenIssuanceIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasHolder()); + EXPECT_FALSE(tx.getHolder().has_value()); + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); + EXPECT_FALSE(tx.hasMPTokenMetadata()); + EXPECT_FALSE(tx.getMPTokenMetadata().has_value()); + EXPECT_FALSE(tx.hasTransferFee()); + EXPECT_FALSE(tx.getTransferFee().has_value()); + EXPECT_FALSE(tx.hasMutableFlags()); + EXPECT_FALSE(tx.getMutableFlags().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/NFTokenAcceptOfferTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenAcceptOfferTests.cpp new file mode 100644 index 0000000000..e2fb8d29ec --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenAcceptOfferTests.cpp @@ -0,0 +1,219 @@ +// Auto-generated unit tests for transaction NFTokenAcceptOffer + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsNFTokenAcceptOfferTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenAcceptOffer")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenBuyOfferValue = canonical_UINT256(); + auto const nFTokenSellOfferValue = canonical_UINT256(); + auto const nFTokenBrokerFeeValue = canonical_AMOUNT(); + + NFTokenAcceptOfferBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setNFTokenBuyOffer(nFTokenBuyOfferValue); + builder.setNFTokenSellOffer(nFTokenSellOfferValue); + builder.setNFTokenBrokerFee(nFTokenBrokerFeeValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = nFTokenBuyOfferValue; + auto const actualOpt = tx.getNFTokenBuyOffer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenBuyOffer should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenBuyOffer"); + EXPECT_TRUE(tx.hasNFTokenBuyOffer()); + } + + { + auto const& expected = nFTokenSellOfferValue; + auto const actualOpt = tx.getNFTokenSellOffer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenSellOffer should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenSellOffer"); + EXPECT_TRUE(tx.hasNFTokenSellOffer()); + } + + { + auto const& expected = nFTokenBrokerFeeValue; + auto const actualOpt = tx.getNFTokenBrokerFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenBrokerFee should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenBrokerFee"); + EXPECT_TRUE(tx.hasNFTokenBrokerFee()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsNFTokenAcceptOfferTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenAcceptOfferFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenBuyOfferValue = canonical_UINT256(); + auto const nFTokenSellOfferValue = canonical_UINT256(); + auto const nFTokenBrokerFeeValue = canonical_AMOUNT(); + + // Build an initial transaction + NFTokenAcceptOfferBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setNFTokenBuyOffer(nFTokenBuyOfferValue); + initialBuilder.setNFTokenSellOffer(nFTokenSellOfferValue); + initialBuilder.setNFTokenBrokerFee(nFTokenBrokerFeeValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + NFTokenAcceptOfferBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = nFTokenBuyOfferValue; + auto const actualOpt = rebuiltTx.getNFTokenBuyOffer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenBuyOffer should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenBuyOffer"); + } + + { + auto const& expected = nFTokenSellOfferValue; + auto const actualOpt = rebuiltTx.getNFTokenSellOffer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenSellOffer should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenSellOffer"); + } + + { + auto const& expected = nFTokenBrokerFeeValue; + auto const actualOpt = rebuiltTx.getNFTokenBrokerFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenBrokerFee should be present"; + expectEqualField(expected, *actualOpt, "sfNFTokenBrokerFee"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenAcceptOfferTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenAcceptOffer{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenAcceptOfferTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenAcceptOfferBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsNFTokenAcceptOfferTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenAcceptOfferNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + NFTokenAcceptOfferBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasNFTokenBuyOffer()); + EXPECT_FALSE(tx.getNFTokenBuyOffer().has_value()); + EXPECT_FALSE(tx.hasNFTokenSellOffer()); + EXPECT_FALSE(tx.getNFTokenSellOffer().has_value()); + EXPECT_FALSE(tx.hasNFTokenBrokerFee()); + EXPECT_FALSE(tx.getNFTokenBrokerFee().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/NFTokenBurnTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenBurnTests.cpp new file mode 100644 index 0000000000..128ff51794 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenBurnTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction NFTokenBurn + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsNFTokenBurnTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenBurn")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const ownerValue = canonical_ACCOUNT(); + + NFTokenBurnBuilder builder{ + accountValue, + nFTokenIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setOwner(ownerValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenIDValue; + auto const actual = tx.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + // Verify optional fields + { + auto const& expected = ownerValue; + auto const actualOpt = tx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + EXPECT_TRUE(tx.hasOwner()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsNFTokenBurnTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenBurnFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const ownerValue = canonical_ACCOUNT(); + + // Build an initial transaction + NFTokenBurnBuilder initialBuilder{ + accountValue, + nFTokenIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setOwner(ownerValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + NFTokenBurnBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenIDValue; + auto const actual = rebuiltTx.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + // Verify optional fields + { + auto const& expected = ownerValue; + auto const actualOpt = rebuiltTx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenBurnTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenBurn{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenBurnTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenBurnBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsNFTokenBurnTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenBurnNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const nFTokenIDValue = canonical_UINT256(); + + NFTokenBurnBuilder builder{ + accountValue, + nFTokenIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasOwner()); + EXPECT_FALSE(tx.getOwner().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/NFTokenCancelOfferTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenCancelOfferTests.cpp new file mode 100644 index 0000000000..f8ab0f7da1 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenCancelOfferTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction NFTokenCancelOffer + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsNFTokenCancelOfferTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenCancelOffer")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenOffersValue = canonical_VECTOR256(); + + NFTokenCancelOfferBuilder builder{ + accountValue, + nFTokenOffersValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenOffersValue; + auto const actual = tx.getNFTokenOffers(); + expectEqualField(expected, actual, "sfNFTokenOffers"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsNFTokenCancelOfferTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenCancelOfferFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenOffersValue = canonical_VECTOR256(); + + // Build an initial transaction + NFTokenCancelOfferBuilder initialBuilder{ + accountValue, + nFTokenOffersValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + NFTokenCancelOfferBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenOffersValue; + auto const actual = rebuiltTx.getNFTokenOffers(); + expectEqualField(expected, actual, "sfNFTokenOffers"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenCancelOfferTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenCancelOffer{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenCancelOfferTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenCancelOfferBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/NFTokenCreateOfferTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenCreateOfferTests.cpp new file mode 100644 index 0000000000..c57ede25c4 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenCreateOfferTests.cpp @@ -0,0 +1,255 @@ +// Auto-generated unit tests for transaction NFTokenCreateOffer + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsNFTokenCreateOfferTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenCreateOffer")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const ownerValue = canonical_ACCOUNT(); + auto const expirationValue = canonical_UINT32(); + + NFTokenCreateOfferBuilder builder{ + accountValue, + nFTokenIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDestination(destinationValue); + builder.setOwner(ownerValue); + builder.setExpiration(expirationValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenIDValue; + auto const actual = tx.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = tx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + EXPECT_TRUE(tx.hasDestination()); + } + + { + auto const& expected = ownerValue; + auto const actualOpt = tx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + EXPECT_TRUE(tx.hasOwner()); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = tx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(tx.hasExpiration()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsNFTokenCreateOfferTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenCreateOfferFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const ownerValue = canonical_ACCOUNT(); + auto const expirationValue = canonical_UINT32(); + + // Build an initial transaction + NFTokenCreateOfferBuilder initialBuilder{ + accountValue, + nFTokenIDValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDestination(destinationValue); + initialBuilder.setOwner(ownerValue); + initialBuilder.setExpiration(expirationValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + NFTokenCreateOfferBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenIDValue; + auto const actual = rebuiltTx.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = rebuiltTx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + } + + { + auto const& expected = ownerValue; + auto const actualOpt = rebuiltTx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = rebuiltTx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenCreateOfferTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenCreateOffer{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenCreateOfferTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenCreateOfferBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsNFTokenCreateOfferTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenCreateOfferNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + NFTokenCreateOfferBuilder builder{ + accountValue, + nFTokenIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDestination()); + EXPECT_FALSE(tx.getDestination().has_value()); + EXPECT_FALSE(tx.hasOwner()); + EXPECT_FALSE(tx.getOwner().has_value()); + EXPECT_FALSE(tx.hasExpiration()); + EXPECT_FALSE(tx.getExpiration().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/NFTokenMintTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenMintTests.cpp new file mode 100644 index 0000000000..e85dbd238c --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenMintTests.cpp @@ -0,0 +1,300 @@ +// Auto-generated unit tests for transaction NFTokenMint + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsNFTokenMintTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenMint")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenTaxonValue = canonical_UINT32(); + auto const transferFeeValue = canonical_UINT16(); + auto const issuerValue = canonical_ACCOUNT(); + auto const uRIValue = canonical_VL(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const expirationValue = canonical_UINT32(); + + NFTokenMintBuilder builder{ + accountValue, + nFTokenTaxonValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setTransferFee(transferFeeValue); + builder.setIssuer(issuerValue); + builder.setURI(uRIValue); + builder.setAmount(amountValue); + builder.setDestination(destinationValue); + builder.setExpiration(expirationValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenTaxonValue; + auto const actual = tx.getNFTokenTaxon(); + expectEqualField(expected, actual, "sfNFTokenTaxon"); + } + + // Verify optional fields + { + auto const& expected = transferFeeValue; + auto const actualOpt = tx.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferFee should be present"; + expectEqualField(expected, *actualOpt, "sfTransferFee"); + EXPECT_TRUE(tx.hasTransferFee()); + } + + { + auto const& expected = issuerValue; + auto const actualOpt = tx.getIssuer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfIssuer should be present"; + expectEqualField(expected, *actualOpt, "sfIssuer"); + EXPECT_TRUE(tx.hasIssuer()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = tx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(tx.hasURI()); + } + + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + + { + auto const& expected = destinationValue; + auto const actualOpt = tx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + EXPECT_TRUE(tx.hasDestination()); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = tx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(tx.hasExpiration()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsNFTokenMintTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenMintFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenTaxonValue = canonical_UINT32(); + auto const transferFeeValue = canonical_UINT16(); + auto const issuerValue = canonical_ACCOUNT(); + auto const uRIValue = canonical_VL(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const expirationValue = canonical_UINT32(); + + // Build an initial transaction + NFTokenMintBuilder initialBuilder{ + accountValue, + nFTokenTaxonValue, + sequenceValue, + feeValue + }; + + initialBuilder.setTransferFee(transferFeeValue); + initialBuilder.setIssuer(issuerValue); + initialBuilder.setURI(uRIValue); + initialBuilder.setAmount(amountValue); + initialBuilder.setDestination(destinationValue); + initialBuilder.setExpiration(expirationValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + NFTokenMintBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenTaxonValue; + auto const actual = rebuiltTx.getNFTokenTaxon(); + expectEqualField(expected, actual, "sfNFTokenTaxon"); + } + + // Verify optional fields + { + auto const& expected = transferFeeValue; + auto const actualOpt = rebuiltTx.getTransferFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferFee should be present"; + expectEqualField(expected, *actualOpt, "sfTransferFee"); + } + + { + auto const& expected = issuerValue; + auto const actualOpt = rebuiltTx.getIssuer(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfIssuer should be present"; + expectEqualField(expected, *actualOpt, "sfIssuer"); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = rebuiltTx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + } + + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + + { + auto const& expected = destinationValue; + auto const actualOpt = rebuiltTx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + } + + { + auto const& expected = expirationValue; + auto const actualOpt = rebuiltTx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenMintTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenMint{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenMintTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenMintBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsNFTokenMintTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenMintNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const nFTokenTaxonValue = canonical_UINT32(); + + NFTokenMintBuilder builder{ + accountValue, + nFTokenTaxonValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasTransferFee()); + EXPECT_FALSE(tx.getTransferFee().has_value()); + EXPECT_FALSE(tx.hasIssuer()); + EXPECT_FALSE(tx.getIssuer().has_value()); + EXPECT_FALSE(tx.hasURI()); + EXPECT_FALSE(tx.getURI().has_value()); + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); + EXPECT_FALSE(tx.hasDestination()); + EXPECT_FALSE(tx.getDestination().has_value()); + EXPECT_FALSE(tx.hasExpiration()); + EXPECT_FALSE(tx.getExpiration().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/NFTokenModifyTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenModifyTests.cpp new file mode 100644 index 0000000000..9f5eeb052d --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/NFTokenModifyTests.cpp @@ -0,0 +1,216 @@ +// Auto-generated unit tests for transaction NFTokenModify + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsNFTokenModifyTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenModify")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const ownerValue = canonical_ACCOUNT(); + auto const uRIValue = canonical_VL(); + + NFTokenModifyBuilder builder{ + accountValue, + nFTokenIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setOwner(ownerValue); + builder.setURI(uRIValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenIDValue; + auto const actual = tx.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + // Verify optional fields + { + auto const& expected = ownerValue; + auto const actualOpt = tx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + EXPECT_TRUE(tx.hasOwner()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = tx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(tx.hasURI()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsNFTokenModifyTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenModifyFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const nFTokenIDValue = canonical_UINT256(); + auto const ownerValue = canonical_ACCOUNT(); + auto const uRIValue = canonical_VL(); + + // Build an initial transaction + NFTokenModifyBuilder initialBuilder{ + accountValue, + nFTokenIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setOwner(ownerValue); + initialBuilder.setURI(uRIValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + NFTokenModifyBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = nFTokenIDValue; + auto const actual = rebuiltTx.getNFTokenID(); + expectEqualField(expected, actual, "sfNFTokenID"); + } + + // Verify optional fields + { + auto const& expected = ownerValue; + auto const actualOpt = rebuiltTx.getOwner(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOwner should be present"; + expectEqualField(expected, *actualOpt, "sfOwner"); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = rebuiltTx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenModifyTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenModify{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsNFTokenModifyTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(NFTokenModifyBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsNFTokenModifyTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testNFTokenModifyNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const nFTokenIDValue = canonical_UINT256(); + + NFTokenModifyBuilder builder{ + accountValue, + nFTokenIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasOwner()); + EXPECT_FALSE(tx.getOwner().has_value()); + EXPECT_FALSE(tx.hasURI()); + EXPECT_FALSE(tx.getURI().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/OfferCancelTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/OfferCancelTests.cpp new file mode 100644 index 0000000000..0e3c8a4224 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/OfferCancelTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction OfferCancel + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsOfferCancelTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOfferCancel")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const offerSequenceValue = canonical_UINT32(); + + OfferCancelBuilder builder{ + accountValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = offerSequenceValue; + auto const actual = tx.getOfferSequence(); + expectEqualField(expected, actual, "sfOfferSequence"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsOfferCancelTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOfferCancelFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const offerSequenceValue = canonical_UINT32(); + + // Build an initial transaction + OfferCancelBuilder initialBuilder{ + accountValue, + offerSequenceValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + OfferCancelBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = offerSequenceValue; + auto const actual = rebuiltTx.getOfferSequence(); + expectEqualField(expected, actual, "sfOfferSequence"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsOfferCancelTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OfferCancel{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsOfferCancelTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OfferCancelBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/OfferCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/OfferCreateTests.cpp new file mode 100644 index 0000000000..3dde69574e --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/OfferCreateTests.cpp @@ -0,0 +1,255 @@ +// Auto-generated unit tests for transaction OfferCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsOfferCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOfferCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const takerPaysValue = canonical_AMOUNT(); + auto const takerGetsValue = canonical_AMOUNT(); + auto const expirationValue = canonical_UINT32(); + auto const offerSequenceValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + + OfferCreateBuilder builder{ + accountValue, + takerPaysValue, + takerGetsValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setExpiration(expirationValue); + builder.setOfferSequence(offerSequenceValue); + builder.setDomainID(domainIDValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = takerPaysValue; + auto const actual = tx.getTakerPays(); + expectEqualField(expected, actual, "sfTakerPays"); + } + + { + auto const& expected = takerGetsValue; + auto const actual = tx.getTakerGets(); + expectEqualField(expected, actual, "sfTakerGets"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = tx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(tx.hasExpiration()); + } + + { + auto const& expected = offerSequenceValue; + auto const actualOpt = tx.getOfferSequence(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOfferSequence should be present"; + expectEqualField(expected, *actualOpt, "sfOfferSequence"); + EXPECT_TRUE(tx.hasOfferSequence()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsOfferCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOfferCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const takerPaysValue = canonical_AMOUNT(); + auto const takerGetsValue = canonical_AMOUNT(); + auto const expirationValue = canonical_UINT32(); + auto const offerSequenceValue = canonical_UINT32(); + auto const domainIDValue = canonical_UINT256(); + + // Build an initial transaction + OfferCreateBuilder initialBuilder{ + accountValue, + takerPaysValue, + takerGetsValue, + sequenceValue, + feeValue + }; + + initialBuilder.setExpiration(expirationValue); + initialBuilder.setOfferSequence(offerSequenceValue); + initialBuilder.setDomainID(domainIDValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + OfferCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = takerPaysValue; + auto const actual = rebuiltTx.getTakerPays(); + expectEqualField(expected, actual, "sfTakerPays"); + } + + { + auto const& expected = takerGetsValue; + auto const actual = rebuiltTx.getTakerGets(); + expectEqualField(expected, actual, "sfTakerGets"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = rebuiltTx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + } + + { + auto const& expected = offerSequenceValue; + auto const actualOpt = rebuiltTx.getOfferSequence(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOfferSequence should be present"; + expectEqualField(expected, *actualOpt, "sfOfferSequence"); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsOfferCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OfferCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsOfferCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OfferCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsOfferCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOfferCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const takerPaysValue = canonical_AMOUNT(); + auto const takerGetsValue = canonical_AMOUNT(); + + OfferCreateBuilder builder{ + accountValue, + takerPaysValue, + takerGetsValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasExpiration()); + EXPECT_FALSE(tx.getExpiration().has_value()); + EXPECT_FALSE(tx.hasOfferSequence()); + EXPECT_FALSE(tx.getOfferSequence().has_value()); + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/OracleDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/OracleDeleteTests.cpp new file mode 100644 index 0000000000..631ad0861a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/OracleDeleteTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction OracleDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsOracleDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOracleDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const oracleDocumentIDValue = canonical_UINT32(); + + OracleDeleteBuilder builder{ + accountValue, + oracleDocumentIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = oracleDocumentIDValue; + auto const actual = tx.getOracleDocumentID(); + expectEqualField(expected, actual, "sfOracleDocumentID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsOracleDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOracleDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const oracleDocumentIDValue = canonical_UINT32(); + + // Build an initial transaction + OracleDeleteBuilder initialBuilder{ + accountValue, + oracleDocumentIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + OracleDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = oracleDocumentIDValue; + auto const actual = rebuiltTx.getOracleDocumentID(); + expectEqualField(expected, actual, "sfOracleDocumentID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsOracleDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OracleDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsOracleDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OracleDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/OracleSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/OracleSetTests.cpp new file mode 100644 index 0000000000..e13e8a8374 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/OracleSetTests.cpp @@ -0,0 +1,273 @@ +// Auto-generated unit tests for transaction OracleSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsOracleSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOracleSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const oracleDocumentIDValue = canonical_UINT32(); + auto const providerValue = canonical_VL(); + auto const uRIValue = canonical_VL(); + auto const assetClassValue = canonical_VL(); + auto const lastUpdateTimeValue = canonical_UINT32(); + auto const priceDataSeriesValue = canonical_ARRAY(); + + OracleSetBuilder builder{ + accountValue, + oracleDocumentIDValue, + lastUpdateTimeValue, + priceDataSeriesValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setProvider(providerValue); + builder.setURI(uRIValue); + builder.setAssetClass(assetClassValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = oracleDocumentIDValue; + auto const actual = tx.getOracleDocumentID(); + expectEqualField(expected, actual, "sfOracleDocumentID"); + } + + { + auto const& expected = lastUpdateTimeValue; + auto const actual = tx.getLastUpdateTime(); + expectEqualField(expected, actual, "sfLastUpdateTime"); + } + + { + auto const& expected = priceDataSeriesValue; + auto const actual = tx.getPriceDataSeries(); + expectEqualField(expected, actual, "sfPriceDataSeries"); + } + + // Verify optional fields + { + auto const& expected = providerValue; + auto const actualOpt = tx.getProvider(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfProvider should be present"; + expectEqualField(expected, *actualOpt, "sfProvider"); + EXPECT_TRUE(tx.hasProvider()); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = tx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + EXPECT_TRUE(tx.hasURI()); + } + + { + auto const& expected = assetClassValue; + auto const actualOpt = tx.getAssetClass(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetClass should be present"; + expectEqualField(expected, *actualOpt, "sfAssetClass"); + EXPECT_TRUE(tx.hasAssetClass()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsOracleSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOracleSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const oracleDocumentIDValue = canonical_UINT32(); + auto const providerValue = canonical_VL(); + auto const uRIValue = canonical_VL(); + auto const assetClassValue = canonical_VL(); + auto const lastUpdateTimeValue = canonical_UINT32(); + auto const priceDataSeriesValue = canonical_ARRAY(); + + // Build an initial transaction + OracleSetBuilder initialBuilder{ + accountValue, + oracleDocumentIDValue, + lastUpdateTimeValue, + priceDataSeriesValue, + sequenceValue, + feeValue + }; + + initialBuilder.setProvider(providerValue); + initialBuilder.setURI(uRIValue); + initialBuilder.setAssetClass(assetClassValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + OracleSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = oracleDocumentIDValue; + auto const actual = rebuiltTx.getOracleDocumentID(); + expectEqualField(expected, actual, "sfOracleDocumentID"); + } + + { + auto const& expected = lastUpdateTimeValue; + auto const actual = rebuiltTx.getLastUpdateTime(); + expectEqualField(expected, actual, "sfLastUpdateTime"); + } + + { + auto const& expected = priceDataSeriesValue; + auto const actual = rebuiltTx.getPriceDataSeries(); + expectEqualField(expected, actual, "sfPriceDataSeries"); + } + + // Verify optional fields + { + auto const& expected = providerValue; + auto const actualOpt = rebuiltTx.getProvider(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfProvider should be present"; + expectEqualField(expected, *actualOpt, "sfProvider"); + } + + { + auto const& expected = uRIValue; + auto const actualOpt = rebuiltTx.getURI(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfURI should be present"; + expectEqualField(expected, *actualOpt, "sfURI"); + } + + { + auto const& expected = assetClassValue; + auto const actualOpt = rebuiltTx.getAssetClass(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetClass should be present"; + expectEqualField(expected, *actualOpt, "sfAssetClass"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsOracleSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OracleSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsOracleSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(OracleSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsOracleSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testOracleSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const oracleDocumentIDValue = canonical_UINT32(); + auto const lastUpdateTimeValue = canonical_UINT32(); + auto const priceDataSeriesValue = canonical_ARRAY(); + + OracleSetBuilder builder{ + accountValue, + oracleDocumentIDValue, + lastUpdateTimeValue, + priceDataSeriesValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasProvider()); + EXPECT_FALSE(tx.getProvider().has_value()); + EXPECT_FALSE(tx.hasURI()); + EXPECT_FALSE(tx.getURI().has_value()); + EXPECT_FALSE(tx.hasAssetClass()); + EXPECT_FALSE(tx.getAssetClass().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelClaimTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelClaimTests.cpp new file mode 100644 index 0000000000..1b742196a5 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelClaimTests.cpp @@ -0,0 +1,279 @@ +// Auto-generated unit tests for transaction PaymentChannelClaim + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsPaymentChannelClaimTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelClaim")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const channelValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const balanceValue = canonical_AMOUNT(); + auto const signatureValue = canonical_VL(); + auto const publicKeyValue = canonical_VL(); + auto const credentialIDsValue = canonical_VECTOR256(); + + PaymentChannelClaimBuilder builder{ + accountValue, + channelValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAmount(amountValue); + builder.setBalance(balanceValue); + builder.setSignature(signatureValue); + builder.setPublicKey(publicKeyValue); + builder.setCredentialIDs(credentialIDsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = channelValue; + auto const actual = tx.getChannel(); + expectEqualField(expected, actual, "sfChannel"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + + { + auto const& expected = balanceValue; + auto const actualOpt = tx.getBalance(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBalance should be present"; + expectEqualField(expected, *actualOpt, "sfBalance"); + EXPECT_TRUE(tx.hasBalance()); + } + + { + auto const& expected = signatureValue; + auto const actualOpt = tx.getSignature(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignature should be present"; + expectEqualField(expected, *actualOpt, "sfSignature"); + EXPECT_TRUE(tx.hasSignature()); + } + + { + auto const& expected = publicKeyValue; + auto const actualOpt = tx.getPublicKey(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPublicKey should be present"; + expectEqualField(expected, *actualOpt, "sfPublicKey"); + EXPECT_TRUE(tx.hasPublicKey()); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = tx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + EXPECT_TRUE(tx.hasCredentialIDs()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsPaymentChannelClaimTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelClaimFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const channelValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const balanceValue = canonical_AMOUNT(); + auto const signatureValue = canonical_VL(); + auto const publicKeyValue = canonical_VL(); + auto const credentialIDsValue = canonical_VECTOR256(); + + // Build an initial transaction + PaymentChannelClaimBuilder initialBuilder{ + accountValue, + channelValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAmount(amountValue); + initialBuilder.setBalance(balanceValue); + initialBuilder.setSignature(signatureValue); + initialBuilder.setPublicKey(publicKeyValue); + initialBuilder.setCredentialIDs(credentialIDsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + PaymentChannelClaimBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = channelValue; + auto const actual = rebuiltTx.getChannel(); + expectEqualField(expected, actual, "sfChannel"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + + { + auto const& expected = balanceValue; + auto const actualOpt = rebuiltTx.getBalance(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBalance should be present"; + expectEqualField(expected, *actualOpt, "sfBalance"); + } + + { + auto const& expected = signatureValue; + auto const actualOpt = rebuiltTx.getSignature(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignature should be present"; + expectEqualField(expected, *actualOpt, "sfSignature"); + } + + { + auto const& expected = publicKeyValue; + auto const actualOpt = rebuiltTx.getPublicKey(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPublicKey should be present"; + expectEqualField(expected, *actualOpt, "sfPublicKey"); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = rebuiltTx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsPaymentChannelClaimTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentChannelClaim{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsPaymentChannelClaimTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentChannelClaimBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsPaymentChannelClaimTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelClaimNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const channelValue = canonical_UINT256(); + + PaymentChannelClaimBuilder builder{ + accountValue, + channelValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); + EXPECT_FALSE(tx.hasBalance()); + EXPECT_FALSE(tx.getBalance().has_value()); + EXPECT_FALSE(tx.hasSignature()); + EXPECT_FALSE(tx.getSignature().has_value()); + EXPECT_FALSE(tx.hasPublicKey()); + EXPECT_FALSE(tx.getPublicKey().has_value()); + EXPECT_FALSE(tx.hasCredentialIDs()); + EXPECT_FALSE(tx.getCredentialIDs().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelCreateTests.cpp new file mode 100644 index 0000000000..e3ba999d0b --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelCreateTests.cpp @@ -0,0 +1,270 @@ +// Auto-generated unit tests for transaction PaymentChannelCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsPaymentChannelCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const settleDelayValue = canonical_UINT32(); + auto const publicKeyValue = canonical_VL(); + auto const cancelAfterValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + + PaymentChannelCreateBuilder builder{ + accountValue, + destinationValue, + amountValue, + settleDelayValue, + publicKeyValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setCancelAfter(cancelAfterValue); + builder.setDestinationTag(destinationTagValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = settleDelayValue; + auto const actual = tx.getSettleDelay(); + expectEqualField(expected, actual, "sfSettleDelay"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = tx.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + // Verify optional fields + { + auto const& expected = cancelAfterValue; + auto const actualOpt = tx.getCancelAfter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCancelAfter should be present"; + expectEqualField(expected, *actualOpt, "sfCancelAfter"); + EXPECT_TRUE(tx.hasCancelAfter()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsPaymentChannelCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const settleDelayValue = canonical_UINT32(); + auto const publicKeyValue = canonical_VL(); + auto const cancelAfterValue = canonical_UINT32(); + auto const destinationTagValue = canonical_UINT32(); + + // Build an initial transaction + PaymentChannelCreateBuilder initialBuilder{ + accountValue, + destinationValue, + amountValue, + settleDelayValue, + publicKeyValue, + sequenceValue, + feeValue + }; + + initialBuilder.setCancelAfter(cancelAfterValue); + initialBuilder.setDestinationTag(destinationTagValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + PaymentChannelCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = settleDelayValue; + auto const actual = rebuiltTx.getSettleDelay(); + expectEqualField(expected, actual, "sfSettleDelay"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = rebuiltTx.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + // Verify optional fields + { + auto const& expected = cancelAfterValue; + auto const actualOpt = rebuiltTx.getCancelAfter(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCancelAfter should be present"; + expectEqualField(expected, *actualOpt, "sfCancelAfter"); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsPaymentChannelCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentChannelCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsPaymentChannelCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentChannelCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsPaymentChannelCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const settleDelayValue = canonical_UINT32(); + auto const publicKeyValue = canonical_VL(); + + PaymentChannelCreateBuilder builder{ + accountValue, + destinationValue, + amountValue, + settleDelayValue, + publicKeyValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasCancelAfter()); + EXPECT_FALSE(tx.getCancelAfter().has_value()); + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelFundTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelFundTests.cpp new file mode 100644 index 0000000000..ce070c0761 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/PaymentChannelFundTests.cpp @@ -0,0 +1,213 @@ +// Auto-generated unit tests for transaction PaymentChannelFund + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsPaymentChannelFundTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelFund")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const channelValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const expirationValue = canonical_UINT32(); + + PaymentChannelFundBuilder builder{ + accountValue, + channelValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setExpiration(expirationValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = channelValue; + auto const actual = tx.getChannel(); + expectEqualField(expected, actual, "sfChannel"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = tx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + EXPECT_TRUE(tx.hasExpiration()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsPaymentChannelFundTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelFundFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const channelValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const expirationValue = canonical_UINT32(); + + // Build an initial transaction + PaymentChannelFundBuilder initialBuilder{ + accountValue, + channelValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setExpiration(expirationValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + PaymentChannelFundBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = channelValue; + auto const actual = rebuiltTx.getChannel(); + expectEqualField(expected, actual, "sfChannel"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = expirationValue; + auto const actualOpt = rebuiltTx.getExpiration(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfExpiration should be present"; + expectEqualField(expected, *actualOpt, "sfExpiration"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsPaymentChannelFundTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentChannelFund{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsPaymentChannelFundTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentChannelFundBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsPaymentChannelFundTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentChannelFundNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const channelValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + PaymentChannelFundBuilder builder{ + accountValue, + channelValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasExpiration()); + EXPECT_FALSE(tx.getExpiration().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/PaymentTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/PaymentTests.cpp new file mode 100644 index 0000000000..7e5c046fca --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/PaymentTests.cpp @@ -0,0 +1,339 @@ +// Auto-generated unit tests for transaction Payment + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsPaymentTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPayment")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const pathsValue = canonical_PATHSET(); + auto const invoiceIDValue = canonical_UINT256(); + auto const destinationTagValue = canonical_UINT32(); + auto const deliverMinValue = canonical_AMOUNT(); + auto const credentialIDsValue = canonical_VECTOR256(); + auto const domainIDValue = canonical_UINT256(); + + PaymentBuilder builder{ + accountValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setSendMax(sendMaxValue); + builder.setPaths(pathsValue); + builder.setInvoiceID(invoiceIDValue); + builder.setDestinationTag(destinationTagValue); + builder.setDeliverMin(deliverMinValue); + builder.setCredentialIDs(credentialIDsValue); + builder.setDomainID(domainIDValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = sendMaxValue; + auto const actualOpt = tx.getSendMax(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSendMax should be present"; + expectEqualField(expected, *actualOpt, "sfSendMax"); + EXPECT_TRUE(tx.hasSendMax()); + } + + { + auto const& expected = pathsValue; + auto const actualOpt = tx.getPaths(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPaths should be present"; + expectEqualField(expected, *actualOpt, "sfPaths"); + EXPECT_TRUE(tx.hasPaths()); + } + + { + auto const& expected = invoiceIDValue; + auto const actualOpt = tx.getInvoiceID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfInvoiceID should be present"; + expectEqualField(expected, *actualOpt, "sfInvoiceID"); + EXPECT_TRUE(tx.hasInvoiceID()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + + { + auto const& expected = deliverMinValue; + auto const actualOpt = tx.getDeliverMin(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDeliverMin should be present"; + expectEqualField(expected, *actualOpt, "sfDeliverMin"); + EXPECT_TRUE(tx.hasDeliverMin()); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = tx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + EXPECT_TRUE(tx.hasCredentialIDs()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsPaymentTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const sendMaxValue = canonical_AMOUNT(); + auto const pathsValue = canonical_PATHSET(); + auto const invoiceIDValue = canonical_UINT256(); + auto const destinationTagValue = canonical_UINT32(); + auto const deliverMinValue = canonical_AMOUNT(); + auto const credentialIDsValue = canonical_VECTOR256(); + auto const domainIDValue = canonical_UINT256(); + + // Build an initial transaction + PaymentBuilder initialBuilder{ + accountValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setSendMax(sendMaxValue); + initialBuilder.setPaths(pathsValue); + initialBuilder.setInvoiceID(invoiceIDValue); + initialBuilder.setDestinationTag(destinationTagValue); + initialBuilder.setDeliverMin(deliverMinValue); + initialBuilder.setCredentialIDs(credentialIDsValue); + initialBuilder.setDomainID(domainIDValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + PaymentBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = sendMaxValue; + auto const actualOpt = rebuiltTx.getSendMax(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSendMax should be present"; + expectEqualField(expected, *actualOpt, "sfSendMax"); + } + + { + auto const& expected = pathsValue; + auto const actualOpt = rebuiltTx.getPaths(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfPaths should be present"; + expectEqualField(expected, *actualOpt, "sfPaths"); + } + + { + auto const& expected = invoiceIDValue; + auto const actualOpt = rebuiltTx.getInvoiceID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfInvoiceID should be present"; + expectEqualField(expected, *actualOpt, "sfInvoiceID"); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + + { + auto const& expected = deliverMinValue; + auto const actualOpt = rebuiltTx.getDeliverMin(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDeliverMin should be present"; + expectEqualField(expected, *actualOpt, "sfDeliverMin"); + } + + { + auto const& expected = credentialIDsValue; + auto const actualOpt = rebuiltTx.getCredentialIDs(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfCredentialIDs should be present"; + expectEqualField(expected, *actualOpt, "sfCredentialIDs"); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsPaymentTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(Payment{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsPaymentTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PaymentBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsPaymentTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPaymentNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + + PaymentBuilder builder{ + accountValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasSendMax()); + EXPECT_FALSE(tx.getSendMax().has_value()); + EXPECT_FALSE(tx.hasPaths()); + EXPECT_FALSE(tx.getPaths().has_value()); + EXPECT_FALSE(tx.hasInvoiceID()); + EXPECT_FALSE(tx.getInvoiceID().has_value()); + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); + EXPECT_FALSE(tx.hasDeliverMin()); + EXPECT_FALSE(tx.getDeliverMin().has_value()); + EXPECT_FALSE(tx.hasCredentialIDs()); + EXPECT_FALSE(tx.getCredentialIDs().has_value()); + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainDeleteTests.cpp new file mode 100644 index 0000000000..e9f92fb5b3 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainDeleteTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction PermissionedDomainDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsPermissionedDomainDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPermissionedDomainDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const domainIDValue = canonical_UINT256(); + + PermissionedDomainDeleteBuilder builder{ + accountValue, + domainIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = domainIDValue; + auto const actual = tx.getDomainID(); + expectEqualField(expected, actual, "sfDomainID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsPermissionedDomainDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPermissionedDomainDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const domainIDValue = canonical_UINT256(); + + // Build an initial transaction + PermissionedDomainDeleteBuilder initialBuilder{ + accountValue, + domainIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + PermissionedDomainDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = domainIDValue; + auto const actual = rebuiltTx.getDomainID(); + expectEqualField(expected, actual, "sfDomainID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsPermissionedDomainDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PermissionedDomainDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsPermissionedDomainDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PermissionedDomainDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainSetTests.cpp new file mode 100644 index 0000000000..eeec170f4c --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/PermissionedDomainSetTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction PermissionedDomainSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsPermissionedDomainSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPermissionedDomainSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const domainIDValue = canonical_UINT256(); + auto const acceptedCredentialsValue = canonical_ARRAY(); + + PermissionedDomainSetBuilder builder{ + accountValue, + acceptedCredentialsValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDomainID(domainIDValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = acceptedCredentialsValue; + auto const actual = tx.getAcceptedCredentials(); + expectEqualField(expected, actual, "sfAcceptedCredentials"); + } + + // Verify optional fields + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsPermissionedDomainSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPermissionedDomainSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const domainIDValue = canonical_UINT256(); + auto const acceptedCredentialsValue = canonical_ARRAY(); + + // Build an initial transaction + PermissionedDomainSetBuilder initialBuilder{ + accountValue, + acceptedCredentialsValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDomainID(domainIDValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + PermissionedDomainSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = acceptedCredentialsValue; + auto const actual = rebuiltTx.getAcceptedCredentials(); + expectEqualField(expected, actual, "sfAcceptedCredentials"); + } + + // Verify optional fields + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsPermissionedDomainSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PermissionedDomainSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsPermissionedDomainSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(PermissionedDomainSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsPermissionedDomainSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testPermissionedDomainSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const acceptedCredentialsValue = canonical_ARRAY(); + + PermissionedDomainSetBuilder builder{ + accountValue, + acceptedCredentialsValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/SetFeeTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/SetFeeTests.cpp new file mode 100644 index 0000000000..981bf72ea7 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/SetFeeTests.cpp @@ -0,0 +1,324 @@ +// Auto-generated unit tests for transaction SetFee + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsSetFeeTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSetFee")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ledgerSequenceValue = canonical_UINT32(); + auto const baseFeeValue = canonical_UINT64(); + auto const referenceFeeUnitsValue = canonical_UINT32(); + auto const reserveBaseValue = canonical_UINT32(); + auto const reserveIncrementValue = canonical_UINT32(); + auto const baseFeeDropsValue = canonical_AMOUNT(); + auto const reserveBaseDropsValue = canonical_AMOUNT(); + auto const reserveIncrementDropsValue = canonical_AMOUNT(); + + SetFeeBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setLedgerSequence(ledgerSequenceValue); + builder.setBaseFee(baseFeeValue); + builder.setReferenceFeeUnits(referenceFeeUnitsValue); + builder.setReserveBase(reserveBaseValue); + builder.setReserveIncrement(reserveIncrementValue); + builder.setBaseFeeDrops(baseFeeDropsValue); + builder.setReserveBaseDrops(reserveBaseDropsValue); + builder.setReserveIncrementDrops(reserveIncrementDropsValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = ledgerSequenceValue; + auto const actualOpt = tx.getLedgerSequence(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLedgerSequence should be present"; + expectEqualField(expected, *actualOpt, "sfLedgerSequence"); + EXPECT_TRUE(tx.hasLedgerSequence()); + } + + { + auto const& expected = baseFeeValue; + auto const actualOpt = tx.getBaseFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBaseFee should be present"; + expectEqualField(expected, *actualOpt, "sfBaseFee"); + EXPECT_TRUE(tx.hasBaseFee()); + } + + { + auto const& expected = referenceFeeUnitsValue; + auto const actualOpt = tx.getReferenceFeeUnits(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReferenceFeeUnits should be present"; + expectEqualField(expected, *actualOpt, "sfReferenceFeeUnits"); + EXPECT_TRUE(tx.hasReferenceFeeUnits()); + } + + { + auto const& expected = reserveBaseValue; + auto const actualOpt = tx.getReserveBase(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveBase should be present"; + expectEqualField(expected, *actualOpt, "sfReserveBase"); + EXPECT_TRUE(tx.hasReserveBase()); + } + + { + auto const& expected = reserveIncrementValue; + auto const actualOpt = tx.getReserveIncrement(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveIncrement should be present"; + expectEqualField(expected, *actualOpt, "sfReserveIncrement"); + EXPECT_TRUE(tx.hasReserveIncrement()); + } + + { + auto const& expected = baseFeeDropsValue; + auto const actualOpt = tx.getBaseFeeDrops(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBaseFeeDrops should be present"; + expectEqualField(expected, *actualOpt, "sfBaseFeeDrops"); + EXPECT_TRUE(tx.hasBaseFeeDrops()); + } + + { + auto const& expected = reserveBaseDropsValue; + auto const actualOpt = tx.getReserveBaseDrops(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveBaseDrops should be present"; + expectEqualField(expected, *actualOpt, "sfReserveBaseDrops"); + EXPECT_TRUE(tx.hasReserveBaseDrops()); + } + + { + auto const& expected = reserveIncrementDropsValue; + auto const actualOpt = tx.getReserveIncrementDrops(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveIncrementDrops should be present"; + expectEqualField(expected, *actualOpt, "sfReserveIncrementDrops"); + EXPECT_TRUE(tx.hasReserveIncrementDrops()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsSetFeeTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSetFeeFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ledgerSequenceValue = canonical_UINT32(); + auto const baseFeeValue = canonical_UINT64(); + auto const referenceFeeUnitsValue = canonical_UINT32(); + auto const reserveBaseValue = canonical_UINT32(); + auto const reserveIncrementValue = canonical_UINT32(); + auto const baseFeeDropsValue = canonical_AMOUNT(); + auto const reserveBaseDropsValue = canonical_AMOUNT(); + auto const reserveIncrementDropsValue = canonical_AMOUNT(); + + // Build an initial transaction + SetFeeBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setLedgerSequence(ledgerSequenceValue); + initialBuilder.setBaseFee(baseFeeValue); + initialBuilder.setReferenceFeeUnits(referenceFeeUnitsValue); + initialBuilder.setReserveBase(reserveBaseValue); + initialBuilder.setReserveIncrement(reserveIncrementValue); + initialBuilder.setBaseFeeDrops(baseFeeDropsValue); + initialBuilder.setReserveBaseDrops(reserveBaseDropsValue); + initialBuilder.setReserveIncrementDrops(reserveIncrementDropsValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + SetFeeBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = ledgerSequenceValue; + auto const actualOpt = rebuiltTx.getLedgerSequence(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLedgerSequence should be present"; + expectEqualField(expected, *actualOpt, "sfLedgerSequence"); + } + + { + auto const& expected = baseFeeValue; + auto const actualOpt = rebuiltTx.getBaseFee(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBaseFee should be present"; + expectEqualField(expected, *actualOpt, "sfBaseFee"); + } + + { + auto const& expected = referenceFeeUnitsValue; + auto const actualOpt = rebuiltTx.getReferenceFeeUnits(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReferenceFeeUnits should be present"; + expectEqualField(expected, *actualOpt, "sfReferenceFeeUnits"); + } + + { + auto const& expected = reserveBaseValue; + auto const actualOpt = rebuiltTx.getReserveBase(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveBase should be present"; + expectEqualField(expected, *actualOpt, "sfReserveBase"); + } + + { + auto const& expected = reserveIncrementValue; + auto const actualOpt = rebuiltTx.getReserveIncrement(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveIncrement should be present"; + expectEqualField(expected, *actualOpt, "sfReserveIncrement"); + } + + { + auto const& expected = baseFeeDropsValue; + auto const actualOpt = rebuiltTx.getBaseFeeDrops(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBaseFeeDrops should be present"; + expectEqualField(expected, *actualOpt, "sfBaseFeeDrops"); + } + + { + auto const& expected = reserveBaseDropsValue; + auto const actualOpt = rebuiltTx.getReserveBaseDrops(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveBaseDrops should be present"; + expectEqualField(expected, *actualOpt, "sfReserveBaseDrops"); + } + + { + auto const& expected = reserveIncrementDropsValue; + auto const actualOpt = rebuiltTx.getReserveIncrementDrops(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfReserveIncrementDrops should be present"; + expectEqualField(expected, *actualOpt, "sfReserveIncrementDrops"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsSetFeeTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(SetFee{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsSetFeeTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(SetFeeBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsSetFeeTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSetFeeNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + SetFeeBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasLedgerSequence()); + EXPECT_FALSE(tx.getLedgerSequence().has_value()); + EXPECT_FALSE(tx.hasBaseFee()); + EXPECT_FALSE(tx.getBaseFee().has_value()); + EXPECT_FALSE(tx.hasReferenceFeeUnits()); + EXPECT_FALSE(tx.getReferenceFeeUnits().has_value()); + EXPECT_FALSE(tx.hasReserveBase()); + EXPECT_FALSE(tx.getReserveBase().has_value()); + EXPECT_FALSE(tx.hasReserveIncrement()); + EXPECT_FALSE(tx.getReserveIncrement().has_value()); + EXPECT_FALSE(tx.hasBaseFeeDrops()); + EXPECT_FALSE(tx.getBaseFeeDrops().has_value()); + EXPECT_FALSE(tx.hasReserveBaseDrops()); + EXPECT_FALSE(tx.getReserveBaseDrops().has_value()); + EXPECT_FALSE(tx.hasReserveIncrementDrops()); + EXPECT_FALSE(tx.getReserveIncrementDrops().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/SetRegularKeyTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/SetRegularKeyTests.cpp new file mode 100644 index 0000000000..ce4f8ce2ef --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/SetRegularKeyTests.cpp @@ -0,0 +1,177 @@ +// Auto-generated unit tests for transaction SetRegularKey + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsSetRegularKeyTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSetRegularKey")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const regularKeyValue = canonical_ACCOUNT(); + + SetRegularKeyBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setRegularKey(regularKeyValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = regularKeyValue; + auto const actualOpt = tx.getRegularKey(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfRegularKey should be present"; + expectEqualField(expected, *actualOpt, "sfRegularKey"); + EXPECT_TRUE(tx.hasRegularKey()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsSetRegularKeyTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSetRegularKeyFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const regularKeyValue = canonical_ACCOUNT(); + + // Build an initial transaction + SetRegularKeyBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setRegularKey(regularKeyValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + SetRegularKeyBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = regularKeyValue; + auto const actualOpt = rebuiltTx.getRegularKey(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfRegularKey should be present"; + expectEqualField(expected, *actualOpt, "sfRegularKey"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsSetRegularKeyTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(SetRegularKey{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsSetRegularKeyTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(SetRegularKeyBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsSetRegularKeyTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSetRegularKeyNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + SetRegularKeyBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasRegularKey()); + EXPECT_FALSE(tx.getRegularKey().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/SignerListSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/SignerListSetTests.cpp new file mode 100644 index 0000000000..8d027823d0 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/SignerListSetTests.cpp @@ -0,0 +1,195 @@ +// Auto-generated unit tests for transaction SignerListSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsSignerListSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSignerListSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const signerQuorumValue = canonical_UINT32(); + auto const signerEntriesValue = canonical_ARRAY(); + + SignerListSetBuilder builder{ + accountValue, + signerQuorumValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setSignerEntries(signerEntriesValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = signerQuorumValue; + auto const actual = tx.getSignerQuorum(); + expectEqualField(expected, actual, "sfSignerQuorum"); + } + + // Verify optional fields + { + auto const& expected = signerEntriesValue; + auto const actualOpt = tx.getSignerEntries(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignerEntries should be present"; + expectEqualField(expected, *actualOpt, "sfSignerEntries"); + EXPECT_TRUE(tx.hasSignerEntries()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsSignerListSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSignerListSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const signerQuorumValue = canonical_UINT32(); + auto const signerEntriesValue = canonical_ARRAY(); + + // Build an initial transaction + SignerListSetBuilder initialBuilder{ + accountValue, + signerQuorumValue, + sequenceValue, + feeValue + }; + + initialBuilder.setSignerEntries(signerEntriesValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + SignerListSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = signerQuorumValue; + auto const actual = rebuiltTx.getSignerQuorum(); + expectEqualField(expected, actual, "sfSignerQuorum"); + } + + // Verify optional fields + { + auto const& expected = signerEntriesValue; + auto const actualOpt = rebuiltTx.getSignerEntries(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignerEntries should be present"; + expectEqualField(expected, *actualOpt, "sfSignerEntries"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsSignerListSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(SignerListSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsSignerListSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(SignerListSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsSignerListSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testSignerListSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const signerQuorumValue = canonical_UINT32(); + + SignerListSetBuilder builder{ + accountValue, + signerQuorumValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasSignerEntries()); + EXPECT_FALSE(tx.getSignerEntries().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/TicketCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/TicketCreateTests.cpp new file mode 100644 index 0000000000..bb07cdef84 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/TicketCreateTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction TicketCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsTicketCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testTicketCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ticketCountValue = canonical_UINT32(); + + TicketCreateBuilder builder{ + accountValue, + ticketCountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ticketCountValue; + auto const actual = tx.getTicketCount(); + expectEqualField(expected, actual, "sfTicketCount"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsTicketCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testTicketCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const ticketCountValue = canonical_UINT32(); + + // Build an initial transaction + TicketCreateBuilder initialBuilder{ + accountValue, + ticketCountValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + TicketCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = ticketCountValue; + auto const actual = rebuiltTx.getTicketCount(); + expectEqualField(expected, actual, "sfTicketCount"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsTicketCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(TicketCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsTicketCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(TicketCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/TrustSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/TrustSetTests.cpp new file mode 100644 index 0000000000..12b243ca5c --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/TrustSetTests.cpp @@ -0,0 +1,219 @@ +// Auto-generated unit tests for transaction TrustSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsTrustSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testTrustSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const limitAmountValue = canonical_AMOUNT(); + auto const qualityInValue = canonical_UINT32(); + auto const qualityOutValue = canonical_UINT32(); + + TrustSetBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setLimitAmount(limitAmountValue); + builder.setQualityIn(qualityInValue); + builder.setQualityOut(qualityOutValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = limitAmountValue; + auto const actualOpt = tx.getLimitAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLimitAmount should be present"; + expectEqualField(expected, *actualOpt, "sfLimitAmount"); + EXPECT_TRUE(tx.hasLimitAmount()); + } + + { + auto const& expected = qualityInValue; + auto const actualOpt = tx.getQualityIn(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfQualityIn should be present"; + expectEqualField(expected, *actualOpt, "sfQualityIn"); + EXPECT_TRUE(tx.hasQualityIn()); + } + + { + auto const& expected = qualityOutValue; + auto const actualOpt = tx.getQualityOut(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfQualityOut should be present"; + expectEqualField(expected, *actualOpt, "sfQualityOut"); + EXPECT_TRUE(tx.hasQualityOut()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsTrustSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testTrustSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const limitAmountValue = canonical_AMOUNT(); + auto const qualityInValue = canonical_UINT32(); + auto const qualityOutValue = canonical_UINT32(); + + // Build an initial transaction + TrustSetBuilder initialBuilder{ + accountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setLimitAmount(limitAmountValue); + initialBuilder.setQualityIn(qualityInValue); + initialBuilder.setQualityOut(qualityOutValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + TrustSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + // Verify optional fields + { + auto const& expected = limitAmountValue; + auto const actualOpt = rebuiltTx.getLimitAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfLimitAmount should be present"; + expectEqualField(expected, *actualOpt, "sfLimitAmount"); + } + + { + auto const& expected = qualityInValue; + auto const actualOpt = rebuiltTx.getQualityIn(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfQualityIn should be present"; + expectEqualField(expected, *actualOpt, "sfQualityIn"); + } + + { + auto const& expected = qualityOutValue; + auto const actualOpt = rebuiltTx.getQualityOut(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfQualityOut should be present"; + expectEqualField(expected, *actualOpt, "sfQualityOut"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsTrustSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(TrustSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsTrustSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(TrustSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsTrustSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testTrustSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + + TrustSetBuilder builder{ + accountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasLimitAmount()); + EXPECT_FALSE(tx.getLimitAmount().has_value()); + EXPECT_FALSE(tx.hasQualityIn()); + EXPECT_FALSE(tx.getQualityIn().has_value()); + EXPECT_FALSE(tx.hasQualityOut()); + EXPECT_FALSE(tx.getQualityOut().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/UNLModifyTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/UNLModifyTests.cpp new file mode 100644 index 0000000000..3481460641 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/UNLModifyTests.cpp @@ -0,0 +1,178 @@ +// Auto-generated unit tests for transaction UNLModify + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsUNLModifyTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testUNLModify")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const uNLModifyDisablingValue = canonical_UINT8(); + auto const ledgerSequenceValue = canonical_UINT32(); + auto const uNLModifyValidatorValue = canonical_VL(); + + UNLModifyBuilder builder{ + accountValue, + uNLModifyDisablingValue, + ledgerSequenceValue, + uNLModifyValidatorValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = uNLModifyDisablingValue; + auto const actual = tx.getUNLModifyDisabling(); + expectEqualField(expected, actual, "sfUNLModifyDisabling"); + } + + { + auto const& expected = ledgerSequenceValue; + auto const actual = tx.getLedgerSequence(); + expectEqualField(expected, actual, "sfLedgerSequence"); + } + + { + auto const& expected = uNLModifyValidatorValue; + auto const actual = tx.getUNLModifyValidator(); + expectEqualField(expected, actual, "sfUNLModifyValidator"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsUNLModifyTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testUNLModifyFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const uNLModifyDisablingValue = canonical_UINT8(); + auto const ledgerSequenceValue = canonical_UINT32(); + auto const uNLModifyValidatorValue = canonical_VL(); + + // Build an initial transaction + UNLModifyBuilder initialBuilder{ + accountValue, + uNLModifyDisablingValue, + ledgerSequenceValue, + uNLModifyValidatorValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + UNLModifyBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = uNLModifyDisablingValue; + auto const actual = rebuiltTx.getUNLModifyDisabling(); + expectEqualField(expected, actual, "sfUNLModifyDisabling"); + } + + { + auto const& expected = ledgerSequenceValue; + auto const actual = rebuiltTx.getLedgerSequence(); + expectEqualField(expected, actual, "sfLedgerSequence"); + } + + { + auto const& expected = uNLModifyValidatorValue; + auto const actual = rebuiltTx.getUNLModifyValidator(); + expectEqualField(expected, actual, "sfUNLModifyValidator"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsUNLModifyTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(UNLModify{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsUNLModifyTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(UNLModifyBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/VaultClawbackTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/VaultClawbackTests.cpp new file mode 100644 index 0000000000..d089e3d097 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/VaultClawbackTests.cpp @@ -0,0 +1,213 @@ +// Auto-generated unit tests for transaction VaultClawback + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsVaultClawbackTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultClawback")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const holderValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + + VaultClawbackBuilder builder{ + accountValue, + vaultIDValue, + holderValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAmount(amountValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = tx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = holderValue; + auto const actual = tx.getHolder(); + expectEqualField(expected, actual, "sfHolder"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = tx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + EXPECT_TRUE(tx.hasAmount()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsVaultClawbackTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultClawbackFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const holderValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + VaultClawbackBuilder initialBuilder{ + accountValue, + vaultIDValue, + holderValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAmount(amountValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + VaultClawbackBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = rebuiltTx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = holderValue; + auto const actual = rebuiltTx.getHolder(); + expectEqualField(expected, actual, "sfHolder"); + } + + // Verify optional fields + { + auto const& expected = amountValue; + auto const actualOpt = rebuiltTx.getAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAmount should be present"; + expectEqualField(expected, *actualOpt, "sfAmount"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsVaultClawbackTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultClawback{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsVaultClawbackTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultClawbackBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsVaultClawbackTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultClawbackNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const vaultIDValue = canonical_UINT256(); + auto const holderValue = canonical_ACCOUNT(); + + VaultClawbackBuilder builder{ + accountValue, + vaultIDValue, + holderValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAmount()); + EXPECT_FALSE(tx.getAmount().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/VaultCreateTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/VaultCreateTests.cpp new file mode 100644 index 0000000000..da141ce812 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/VaultCreateTests.cpp @@ -0,0 +1,300 @@ +// Auto-generated unit tests for transaction VaultCreate + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsVaultCreateTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultCreate")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const assetsMaximumValue = canonical_NUMBER(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const domainIDValue = canonical_UINT256(); + auto const withdrawalPolicyValue = canonical_UINT8(); + auto const dataValue = canonical_VL(); + auto const scaleValue = canonical_UINT8(); + + VaultCreateBuilder builder{ + accountValue, + assetValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAssetsMaximum(assetsMaximumValue); + builder.setMPTokenMetadata(mPTokenMetadataValue); + builder.setDomainID(domainIDValue); + builder.setWithdrawalPolicy(withdrawalPolicyValue); + builder.setData(dataValue); + builder.setScale(scaleValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = tx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + // Verify optional fields + { + auto const& expected = assetsMaximumValue; + auto const actualOpt = tx.getAssetsMaximum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetsMaximum should be present"; + expectEqualField(expected, *actualOpt, "sfAssetsMaximum"); + EXPECT_TRUE(tx.hasAssetsMaximum()); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = tx.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMPTokenMetadata should be present"; + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + EXPECT_TRUE(tx.hasMPTokenMetadata()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + + { + auto const& expected = withdrawalPolicyValue; + auto const actualOpt = tx.getWithdrawalPolicy(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWithdrawalPolicy should be present"; + expectEqualField(expected, *actualOpt, "sfWithdrawalPolicy"); + EXPECT_TRUE(tx.hasWithdrawalPolicy()); + } + + { + auto const& expected = dataValue; + auto const actualOpt = tx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(tx.hasData()); + } + + { + auto const& expected = scaleValue; + auto const actualOpt = tx.getScale(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfScale should be present"; + expectEqualField(expected, *actualOpt, "sfScale"); + EXPECT_TRUE(tx.hasScale()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsVaultCreateTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultCreateFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const assetValue = canonical_ISSUE(); + auto const assetsMaximumValue = canonical_NUMBER(); + auto const mPTokenMetadataValue = canonical_VL(); + auto const domainIDValue = canonical_UINT256(); + auto const withdrawalPolicyValue = canonical_UINT8(); + auto const dataValue = canonical_VL(); + auto const scaleValue = canonical_UINT8(); + + // Build an initial transaction + VaultCreateBuilder initialBuilder{ + accountValue, + assetValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAssetsMaximum(assetsMaximumValue); + initialBuilder.setMPTokenMetadata(mPTokenMetadataValue); + initialBuilder.setDomainID(domainIDValue); + initialBuilder.setWithdrawalPolicy(withdrawalPolicyValue); + initialBuilder.setData(dataValue); + initialBuilder.setScale(scaleValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + VaultCreateBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = assetValue; + auto const actual = rebuiltTx.getAsset(); + expectEqualField(expected, actual, "sfAsset"); + } + + // Verify optional fields + { + auto const& expected = assetsMaximumValue; + auto const actualOpt = rebuiltTx.getAssetsMaximum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetsMaximum should be present"; + expectEqualField(expected, *actualOpt, "sfAssetsMaximum"); + } + + { + auto const& expected = mPTokenMetadataValue; + auto const actualOpt = rebuiltTx.getMPTokenMetadata(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMPTokenMetadata should be present"; + expectEqualField(expected, *actualOpt, "sfMPTokenMetadata"); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + + { + auto const& expected = withdrawalPolicyValue; + auto const actualOpt = rebuiltTx.getWithdrawalPolicy(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWithdrawalPolicy should be present"; + expectEqualField(expected, *actualOpt, "sfWithdrawalPolicy"); + } + + { + auto const& expected = dataValue; + auto const actualOpt = rebuiltTx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + } + + { + auto const& expected = scaleValue; + auto const actualOpt = rebuiltTx.getScale(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfScale should be present"; + expectEqualField(expected, *actualOpt, "sfScale"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsVaultCreateTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultCreate{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsVaultCreateTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultCreateBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsVaultCreateTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultCreateNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const assetValue = canonical_ISSUE(); + + VaultCreateBuilder builder{ + accountValue, + assetValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAssetsMaximum()); + EXPECT_FALSE(tx.getAssetsMaximum().has_value()); + EXPECT_FALSE(tx.hasMPTokenMetadata()); + EXPECT_FALSE(tx.getMPTokenMetadata().has_value()); + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); + EXPECT_FALSE(tx.hasWithdrawalPolicy()); + EXPECT_FALSE(tx.getWithdrawalPolicy().has_value()); + EXPECT_FALSE(tx.hasData()); + EXPECT_FALSE(tx.getData().has_value()); + EXPECT_FALSE(tx.hasScale()); + EXPECT_FALSE(tx.getScale().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/VaultDeleteTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/VaultDeleteTests.cpp new file mode 100644 index 0000000000..24c89d249a --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/VaultDeleteTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction VaultDelete + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsVaultDeleteTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultDelete")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + + VaultDeleteBuilder builder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = tx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsVaultDeleteTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultDeleteFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + + // Build an initial transaction + VaultDeleteBuilder initialBuilder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + VaultDeleteBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = rebuiltTx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsVaultDeleteTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultDelete{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsVaultDeleteTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultDeleteBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/VaultDepositTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/VaultDepositTests.cpp new file mode 100644 index 0000000000..c18ee8bd62 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/VaultDepositTests.cpp @@ -0,0 +1,162 @@ +// Auto-generated unit tests for transaction VaultDeposit + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsVaultDepositTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultDeposit")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + VaultDepositBuilder builder{ + accountValue, + vaultIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = tx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsVaultDepositTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultDepositFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + VaultDepositBuilder initialBuilder{ + accountValue, + vaultIDValue, + amountValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + VaultDepositBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = rebuiltTx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsVaultDepositTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultDeposit{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsVaultDepositTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultDepositBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/VaultSetTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/VaultSetTests.cpp new file mode 100644 index 0000000000..995c1019f3 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/VaultSetTests.cpp @@ -0,0 +1,237 @@ +// Auto-generated unit tests for transaction VaultSet + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsVaultSetTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultSet")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const assetsMaximumValue = canonical_NUMBER(); + auto const domainIDValue = canonical_UINT256(); + auto const dataValue = canonical_VL(); + + VaultSetBuilder builder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setAssetsMaximum(assetsMaximumValue); + builder.setDomainID(domainIDValue); + builder.setData(dataValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = tx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + // Verify optional fields + { + auto const& expected = assetsMaximumValue; + auto const actualOpt = tx.getAssetsMaximum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetsMaximum should be present"; + expectEqualField(expected, *actualOpt, "sfAssetsMaximum"); + EXPECT_TRUE(tx.hasAssetsMaximum()); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = tx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + EXPECT_TRUE(tx.hasDomainID()); + } + + { + auto const& expected = dataValue; + auto const actualOpt = tx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + EXPECT_TRUE(tx.hasData()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsVaultSetTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultSetFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const assetsMaximumValue = canonical_NUMBER(); + auto const domainIDValue = canonical_UINT256(); + auto const dataValue = canonical_VL(); + + // Build an initial transaction + VaultSetBuilder initialBuilder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setAssetsMaximum(assetsMaximumValue); + initialBuilder.setDomainID(domainIDValue); + initialBuilder.setData(dataValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + VaultSetBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = rebuiltTx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + // Verify optional fields + { + auto const& expected = assetsMaximumValue; + auto const actualOpt = rebuiltTx.getAssetsMaximum(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfAssetsMaximum should be present"; + expectEqualField(expected, *actualOpt, "sfAssetsMaximum"); + } + + { + auto const& expected = domainIDValue; + auto const actualOpt = rebuiltTx.getDomainID(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomainID should be present"; + expectEqualField(expected, *actualOpt, "sfDomainID"); + } + + { + auto const& expected = dataValue; + auto const actualOpt = rebuiltTx.getData(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfData should be present"; + expectEqualField(expected, *actualOpt, "sfData"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsVaultSetTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultSet{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsVaultSetTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultSetBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsVaultSetTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultSetNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const vaultIDValue = canonical_UINT256(); + + VaultSetBuilder builder{ + accountValue, + vaultIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasAssetsMaximum()); + EXPECT_FALSE(tx.getAssetsMaximum().has_value()); + EXPECT_FALSE(tx.hasDomainID()); + EXPECT_FALSE(tx.getDomainID().has_value()); + EXPECT_FALSE(tx.hasData()); + EXPECT_FALSE(tx.getData().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/VaultWithdrawTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/VaultWithdrawTests.cpp new file mode 100644 index 0000000000..9d8a7fecb9 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/VaultWithdrawTests.cpp @@ -0,0 +1,234 @@ +// Auto-generated unit tests for transaction VaultWithdraw + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsVaultWithdrawTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultWithdraw")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + + VaultWithdrawBuilder builder{ + accountValue, + vaultIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDestination(destinationValue); + builder.setDestinationTag(destinationTagValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = tx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = tx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + EXPECT_TRUE(tx.hasDestination()); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsVaultWithdrawTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultWithdrawFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const vaultIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + + // Build an initial transaction + VaultWithdrawBuilder initialBuilder{ + accountValue, + vaultIDValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDestination(destinationValue); + initialBuilder.setDestinationTag(destinationTagValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + VaultWithdrawBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = vaultIDValue; + auto const actual = rebuiltTx.getVaultID(); + expectEqualField(expected, actual, "sfVaultID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = rebuiltTx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + } + + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsVaultWithdrawTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultWithdraw{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsVaultWithdrawTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(VaultWithdrawBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsVaultWithdrawTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testVaultWithdrawNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const vaultIDValue = canonical_UINT256(); + auto const amountValue = canonical_AMOUNT(); + + VaultWithdrawBuilder builder{ + accountValue, + vaultIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDestination()); + EXPECT_FALSE(tx.getDestination().has_value()); + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp new file mode 100644 index 0000000000..c3f2f11a00 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainAccountCreateCommitTests.cpp @@ -0,0 +1,194 @@ +// Auto-generated unit tests for transaction XChainAccountCreateCommit + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainAccountCreateCommitTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAccountCreateCommit")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + + XChainAccountCreateCommitBuilder builder{ + accountValue, + xChainBridgeValue, + destinationValue, + amountValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = tx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainAccountCreateCommitTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAccountCreateCommitFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + + // Build an initial transaction + XChainAccountCreateCommitBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + destinationValue, + amountValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainAccountCreateCommitBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = rebuiltTx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainAccountCreateCommitTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainAccountCreateCommit{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainAccountCreateCommitTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainAccountCreateCommitBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp new file mode 100644 index 0000000000..82f9c6afc1 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainAddAccountCreateAttestationTests.cpp @@ -0,0 +1,306 @@ +// Auto-generated unit tests for transaction XChainAddAccountCreateAttestation + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainAddAccountCreateAttestationTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAddAccountCreateAttestation")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const attestationSignerAccountValue = canonical_ACCOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const signatureValue = canonical_VL(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const attestationRewardAccountValue = canonical_ACCOUNT(); + auto const wasLockingChainSendValue = canonical_UINT8(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + + XChainAddAccountCreateAttestationBuilder builder{ + accountValue, + xChainBridgeValue, + attestationSignerAccountValue, + publicKeyValue, + signatureValue, + otherChainSourceValue, + amountValue, + attestationRewardAccountValue, + wasLockingChainSendValue, + xChainAccountCreateCountValue, + destinationValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = attestationSignerAccountValue; + auto const actual = tx.getAttestationSignerAccount(); + expectEqualField(expected, actual, "sfAttestationSignerAccount"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = tx.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + { + auto const& expected = signatureValue; + auto const actual = tx.getSignature(); + expectEqualField(expected, actual, "sfSignature"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = tx.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = attestationRewardAccountValue; + auto const actual = tx.getAttestationRewardAccount(); + expectEqualField(expected, actual, "sfAttestationRewardAccount"); + } + + { + auto const& expected = wasLockingChainSendValue; + auto const actual = tx.getWasLockingChainSend(); + expectEqualField(expected, actual, "sfWasLockingChainSend"); + } + + { + auto const& expected = xChainAccountCreateCountValue; + auto const actual = tx.getXChainAccountCreateCount(); + expectEqualField(expected, actual, "sfXChainAccountCreateCount"); + } + + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = tx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainAddAccountCreateAttestationTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAddAccountCreateAttestationFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const attestationSignerAccountValue = canonical_ACCOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const signatureValue = canonical_VL(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const attestationRewardAccountValue = canonical_ACCOUNT(); + auto const wasLockingChainSendValue = canonical_UINT8(); + auto const xChainAccountCreateCountValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const signatureRewardValue = canonical_AMOUNT(); + + // Build an initial transaction + XChainAddAccountCreateAttestationBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + attestationSignerAccountValue, + publicKeyValue, + signatureValue, + otherChainSourceValue, + amountValue, + attestationRewardAccountValue, + wasLockingChainSendValue, + xChainAccountCreateCountValue, + destinationValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainAddAccountCreateAttestationBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = attestationSignerAccountValue; + auto const actual = rebuiltTx.getAttestationSignerAccount(); + expectEqualField(expected, actual, "sfAttestationSignerAccount"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = rebuiltTx.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + { + auto const& expected = signatureValue; + auto const actual = rebuiltTx.getSignature(); + expectEqualField(expected, actual, "sfSignature"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = rebuiltTx.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = attestationRewardAccountValue; + auto const actual = rebuiltTx.getAttestationRewardAccount(); + expectEqualField(expected, actual, "sfAttestationRewardAccount"); + } + + { + auto const& expected = wasLockingChainSendValue; + auto const actual = rebuiltTx.getWasLockingChainSend(); + expectEqualField(expected, actual, "sfWasLockingChainSend"); + } + + { + auto const& expected = xChainAccountCreateCountValue; + auto const actual = rebuiltTx.getXChainAccountCreateCount(); + expectEqualField(expected, actual, "sfXChainAccountCreateCount"); + } + + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = rebuiltTx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainAddAccountCreateAttestationTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainAddAccountCreateAttestation{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainAddAccountCreateAttestationTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainAddAccountCreateAttestationBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp new file mode 100644 index 0000000000..6b9144fa68 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainAddClaimAttestationTests.cpp @@ -0,0 +1,339 @@ +// Auto-generated unit tests for transaction XChainAddClaimAttestation + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainAddClaimAttestationTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAddClaimAttestation")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const attestationSignerAccountValue = canonical_ACCOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const signatureValue = canonical_VL(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const attestationRewardAccountValue = canonical_ACCOUNT(); + auto const wasLockingChainSendValue = canonical_UINT8(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + + XChainAddClaimAttestationBuilder builder{ + accountValue, + xChainBridgeValue, + attestationSignerAccountValue, + publicKeyValue, + signatureValue, + otherChainSourceValue, + amountValue, + attestationRewardAccountValue, + wasLockingChainSendValue, + xChainClaimIDValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDestination(destinationValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = attestationSignerAccountValue; + auto const actual = tx.getAttestationSignerAccount(); + expectEqualField(expected, actual, "sfAttestationSignerAccount"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = tx.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + { + auto const& expected = signatureValue; + auto const actual = tx.getSignature(); + expectEqualField(expected, actual, "sfSignature"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = tx.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = attestationRewardAccountValue; + auto const actual = tx.getAttestationRewardAccount(); + expectEqualField(expected, actual, "sfAttestationRewardAccount"); + } + + { + auto const& expected = wasLockingChainSendValue; + auto const actual = tx.getWasLockingChainSend(); + expectEqualField(expected, actual, "sfWasLockingChainSend"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = tx.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = tx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + EXPECT_TRUE(tx.hasDestination()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainAddClaimAttestationTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAddClaimAttestationFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const attestationSignerAccountValue = canonical_ACCOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const signatureValue = canonical_VL(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const attestationRewardAccountValue = canonical_ACCOUNT(); + auto const wasLockingChainSendValue = canonical_UINT8(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + + // Build an initial transaction + XChainAddClaimAttestationBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + attestationSignerAccountValue, + publicKeyValue, + signatureValue, + otherChainSourceValue, + amountValue, + attestationRewardAccountValue, + wasLockingChainSendValue, + xChainClaimIDValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDestination(destinationValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainAddClaimAttestationBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = attestationSignerAccountValue; + auto const actual = rebuiltTx.getAttestationSignerAccount(); + expectEqualField(expected, actual, "sfAttestationSignerAccount"); + } + + { + auto const& expected = publicKeyValue; + auto const actual = rebuiltTx.getPublicKey(); + expectEqualField(expected, actual, "sfPublicKey"); + } + + { + auto const& expected = signatureValue; + auto const actual = rebuiltTx.getSignature(); + expectEqualField(expected, actual, "sfSignature"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = rebuiltTx.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + { + auto const& expected = attestationRewardAccountValue; + auto const actual = rebuiltTx.getAttestationRewardAccount(); + expectEqualField(expected, actual, "sfAttestationRewardAccount"); + } + + { + auto const& expected = wasLockingChainSendValue; + auto const actual = rebuiltTx.getWasLockingChainSend(); + expectEqualField(expected, actual, "sfWasLockingChainSend"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = rebuiltTx.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + // Verify optional fields + { + auto const& expected = destinationValue; + auto const actualOpt = rebuiltTx.getDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestination should be present"; + expectEqualField(expected, *actualOpt, "sfDestination"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainAddClaimAttestationTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainAddClaimAttestation{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainAddClaimAttestationTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainAddClaimAttestationBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsXChainAddClaimAttestationTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainAddClaimAttestationNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const attestationSignerAccountValue = canonical_ACCOUNT(); + auto const publicKeyValue = canonical_VL(); + auto const signatureValue = canonical_VL(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + auto const attestationRewardAccountValue = canonical_ACCOUNT(); + auto const wasLockingChainSendValue = canonical_UINT8(); + auto const xChainClaimIDValue = canonical_UINT64(); + + XChainAddClaimAttestationBuilder builder{ + accountValue, + xChainBridgeValue, + attestationSignerAccountValue, + publicKeyValue, + signatureValue, + otherChainSourceValue, + amountValue, + attestationRewardAccountValue, + wasLockingChainSendValue, + xChainClaimIDValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDestination()); + EXPECT_FALSE(tx.getDestination().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp new file mode 100644 index 0000000000..69101c843d --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainClaimTests.cpp @@ -0,0 +1,249 @@ +// Auto-generated unit tests for transaction XChainClaim + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainClaimTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainClaim")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + auto const amountValue = canonical_AMOUNT(); + + XChainClaimBuilder builder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setDestinationTag(destinationTagValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = tx.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + { + auto const& expected = destinationValue; + auto const actual = tx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationTagValue; + auto const actualOpt = tx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + EXPECT_TRUE(tx.hasDestinationTag()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainClaimTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainClaimFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const destinationTagValue = canonical_UINT32(); + auto const amountValue = canonical_AMOUNT(); + + // Build an initial transaction + XChainClaimBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setDestinationTag(destinationTagValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainClaimBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = rebuiltTx.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + { + auto const& expected = destinationValue; + auto const actual = rebuiltTx.getDestination(); + expectEqualField(expected, actual, "sfDestination"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = destinationTagValue; + auto const actualOpt = rebuiltTx.getDestinationTag(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDestinationTag should be present"; + expectEqualField(expected, *actualOpt, "sfDestinationTag"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainClaimTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainClaim{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainClaimTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainClaimBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsXChainClaimTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainClaimNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const destinationValue = canonical_ACCOUNT(); + auto const amountValue = canonical_AMOUNT(); + + XChainClaimBuilder builder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + destinationValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasDestinationTag()); + EXPECT_FALSE(tx.getDestinationTag().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp new file mode 100644 index 0000000000..e6c72ec908 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainCommitTests.cpp @@ -0,0 +1,231 @@ +// Auto-generated unit tests for transaction XChainCommit + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainCommitTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCommit")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const amountValue = canonical_AMOUNT(); + auto const otherChainDestinationValue = canonical_ACCOUNT(); + + XChainCommitBuilder builder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setOtherChainDestination(otherChainDestinationValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = tx.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + { + auto const& expected = amountValue; + auto const actual = tx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = otherChainDestinationValue; + auto const actualOpt = tx.getOtherChainDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOtherChainDestination should be present"; + expectEqualField(expected, *actualOpt, "sfOtherChainDestination"); + EXPECT_TRUE(tx.hasOtherChainDestination()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainCommitTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCommitFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const amountValue = canonical_AMOUNT(); + auto const otherChainDestinationValue = canonical_ACCOUNT(); + + // Build an initial transaction + XChainCommitBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + amountValue, + sequenceValue, + feeValue + }; + + initialBuilder.setOtherChainDestination(otherChainDestinationValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainCommitBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = xChainClaimIDValue; + auto const actual = rebuiltTx.getXChainClaimID(); + expectEqualField(expected, actual, "sfXChainClaimID"); + } + + { + auto const& expected = amountValue; + auto const actual = rebuiltTx.getAmount(); + expectEqualField(expected, actual, "sfAmount"); + } + + // Verify optional fields + { + auto const& expected = otherChainDestinationValue; + auto const actualOpt = rebuiltTx.getOtherChainDestination(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfOtherChainDestination should be present"; + expectEqualField(expected, *actualOpt, "sfOtherChainDestination"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainCommitTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainCommit{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainCommitTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainCommitBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsXChainCommitTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCommitNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const xChainClaimIDValue = canonical_UINT64(); + auto const amountValue = canonical_AMOUNT(); + + XChainCommitBuilder builder{ + accountValue, + xChainBridgeValue, + xChainClaimIDValue, + amountValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasOtherChainDestination()); + EXPECT_FALSE(tx.getOtherChainDestination().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp new file mode 100644 index 0000000000..5f529440f3 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateBridgeTests.cpp @@ -0,0 +1,213 @@ +// Auto-generated unit tests for transaction XChainCreateBridge + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainCreateBridgeTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCreateBridge")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const minAccountCreateAmountValue = canonical_AMOUNT(); + + XChainCreateBridgeBuilder builder{ + accountValue, + xChainBridgeValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setMinAccountCreateAmount(minAccountCreateAmountValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = tx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + // Verify optional fields + { + auto const& expected = minAccountCreateAmountValue; + auto const actualOpt = tx.getMinAccountCreateAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; + expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); + EXPECT_TRUE(tx.hasMinAccountCreateAmount()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainCreateBridgeTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCreateBridgeFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const minAccountCreateAmountValue = canonical_AMOUNT(); + + // Build an initial transaction + XChainCreateBridgeBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + initialBuilder.setMinAccountCreateAmount(minAccountCreateAmountValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainCreateBridgeBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = rebuiltTx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + // Verify optional fields + { + auto const& expected = minAccountCreateAmountValue; + auto const actualOpt = rebuiltTx.getMinAccountCreateAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; + expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainCreateBridgeTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainCreateBridge{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainCreateBridgeTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainCreateBridgeBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsXChainCreateBridgeTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCreateBridgeNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + + XChainCreateBridgeBuilder builder{ + accountValue, + xChainBridgeValue, + signatureRewardValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasMinAccountCreateAmount()); + EXPECT_FALSE(tx.getMinAccountCreateAmount().has_value()); +} + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp new file mode 100644 index 0000000000..41c71b9d8d --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainCreateClaimIDTests.cpp @@ -0,0 +1,178 @@ +// Auto-generated unit tests for transaction XChainCreateClaimID + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainCreateClaimIDTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCreateClaimID")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + + XChainCreateClaimIDBuilder builder{ + accountValue, + xChainBridgeValue, + signatureRewardValue, + otherChainSourceValue, + sequenceValue, + feeValue + }; + + // Set optional fields + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = tx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = tx.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + // Verify optional fields +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainCreateClaimIDTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainCreateClaimIDFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const otherChainSourceValue = canonical_ACCOUNT(); + + // Build an initial transaction + XChainCreateClaimIDBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + signatureRewardValue, + otherChainSourceValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainCreateClaimIDBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + { + auto const& expected = signatureRewardValue; + auto const actual = rebuiltTx.getSignatureReward(); + expectEqualField(expected, actual, "sfSignatureReward"); + } + + { + auto const& expected = otherChainSourceValue; + auto const actual = rebuiltTx.getOtherChainSource(); + expectEqualField(expected, actual, "sfOtherChainSource"); + } + + // Verify optional fields +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainCreateClaimIDTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainCreateClaimID{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainCreateClaimIDTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainCreateClaimIDBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + + +} diff --git a/src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp new file mode 100644 index 0000000000..7b3c4be5ce --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/XChainModifyBridgeTests.cpp @@ -0,0 +1,216 @@ +// Auto-generated unit tests for transaction XChainModifyBridge + + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace xrpl::transactions { + +// 1 & 4) Set fields via builder setters, build, then read them back via +// wrapper getters. After build(), validate() should succeed. +TEST(TransactionsXChainModifyBridgeTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainModifyBridge")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 1; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const minAccountCreateAmountValue = canonical_AMOUNT(); + + XChainModifyBridgeBuilder builder{ + accountValue, + xChainBridgeValue, + sequenceValue, + feeValue + }; + + // Set optional fields + builder.setSignatureReward(signatureRewardValue); + builder.setMinAccountCreateAmount(minAccountCreateAmountValue); + + auto tx = builder.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(tx.validate(reason)) << reason; + + // Verify signing was applied + EXPECT_FALSE(tx.getSigningPubKey().empty()); + EXPECT_TRUE(tx.hasTxnSignature()); + + // Verify common fields + EXPECT_EQ(tx.getAccount(), accountValue); + EXPECT_EQ(tx.getSequence(), sequenceValue); + EXPECT_EQ(tx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = tx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + // Verify optional fields + { + auto const& expected = signatureRewardValue; + auto const actualOpt = tx.getSignatureReward(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignatureReward should be present"; + expectEqualField(expected, *actualOpt, "sfSignatureReward"); + EXPECT_TRUE(tx.hasSignatureReward()); + } + + { + auto const& expected = minAccountCreateAmountValue; + auto const actualOpt = tx.getMinAccountCreateAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; + expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); + EXPECT_TRUE(tx.hasMinAccountCreateAmount()); + } + +} + +// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper, +// and verify all fields match. +TEST(TransactionsXChainModifyBridgeTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainModifyBridgeFromTx")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 2; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + auto const signatureRewardValue = canonical_AMOUNT(); + auto const minAccountCreateAmountValue = canonical_AMOUNT(); + + // Build an initial transaction + XChainModifyBridgeBuilder initialBuilder{ + accountValue, + xChainBridgeValue, + sequenceValue, + feeValue + }; + + initialBuilder.setSignatureReward(signatureRewardValue); + initialBuilder.setMinAccountCreateAmount(minAccountCreateAmountValue); + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + XChainModifyBridgeBuilder builderFromTx{initialTx.getSTTx()}; + + auto rebuiltTx = builderFromTx.build(publicKey, secretKey); + + std::string reason; + EXPECT_TRUE(rebuiltTx.validate(reason)) << reason; + + // Verify common fields + EXPECT_EQ(rebuiltTx.getAccount(), accountValue); + EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue); + EXPECT_EQ(rebuiltTx.getFee(), feeValue); + + // Verify required fields + { + auto const& expected = xChainBridgeValue; + auto const actual = rebuiltTx.getXChainBridge(); + expectEqualField(expected, actual, "sfXChainBridge"); + } + + // Verify optional fields + { + auto const& expected = signatureRewardValue; + auto const actualOpt = rebuiltTx.getSignatureReward(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSignatureReward should be present"; + expectEqualField(expected, *actualOpt, "sfSignatureReward"); + } + + { + auto const& expected = minAccountCreateAmountValue; + auto const actualOpt = rebuiltTx.getMinAccountCreateAmount(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMinAccountCreateAmount should be present"; + expectEqualField(expected, *actualOpt, "sfMinAccountCreateAmount"); + } + +} + +// 3) Verify wrapper throws when constructed from wrong transaction type. +TEST(TransactionsXChainModifyBridgeTests, WrapperThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainModifyBridge{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsXChainModifyBridgeTests, BuilderThrowsOnWrongTxType) +{ + // Build a valid transaction of a different type + auto const [pk, sk] = + generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder")); + auto const account = calcAccountID(pk); + + AccountSetBuilder wrongBuilder{account, 1, canonical_AMOUNT()}; + auto wrongTx = wrongBuilder.build(pk, sk); + + EXPECT_THROW(XChainModifyBridgeBuilder{wrongTx.getSTTx()}, std::runtime_error); +} + +// 5) Build with only required fields and verify optional fields return nullopt. +TEST(TransactionsXChainModifyBridgeTests, OptionalFieldsReturnNullopt) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::secp256k1, generateSeed("testXChainModifyBridgeNullopt")); + + // Common transaction fields + auto const accountValue = calcAccountID(publicKey); + std::uint32_t const sequenceValue = 3; + auto const feeValue = canonical_AMOUNT(); + + // Transaction-specific required field values + auto const xChainBridgeValue = canonical_XCHAIN_BRIDGE(); + + XChainModifyBridgeBuilder builder{ + accountValue, + xChainBridgeValue, + sequenceValue, + feeValue + }; + + // Do NOT set optional fields + + auto tx = builder.build(publicKey, secretKey); + + // Verify optional fields are not present + EXPECT_FALSE(tx.hasSignatureReward()); + EXPECT_FALSE(tx.getSignatureReward().has_value()); + EXPECT_FALSE(tx.hasMinAccountCreateAmount()); + EXPECT_FALSE(tx.getMinAccountCreateAmount().has_value()); +} + +} From 12954d5392294338081ba941012e9b5055a5cbaa Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Wed, 18 Mar 2026 22:41:09 +0000 Subject: [PATCH 05/16] fix: Address remaining issue after clang-tidy merge (#6582) --- src/tests/libxrpl/basics/MallocTrim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/libxrpl/basics/MallocTrim.cpp b/src/tests/libxrpl/basics/MallocTrim.cpp index f01bd91bbf..483cf37fe2 100644 --- a/src/tests/libxrpl/basics/MallocTrim.cpp +++ b/src/tests/libxrpl/basics/MallocTrim.cpp @@ -89,7 +89,7 @@ TEST(parseStatmRSSkB, standard_format) // Test empty string { - std::string statm = ""; + std::string statm; long result = parseStatmRSSkB(statm); EXPECT_EQ(result, -1); } From 6efd31229aad51ee208ebcf39fcbd4b84e689d09 Mon Sep 17 00:00:00 2001 From: Michael Legleux Date: Thu, 19 Mar 2026 03:23:51 -0700 Subject: [PATCH 06/16] fix: Use correct format and event for workflows for release tags (#6554) --- .github/actions/generate-version/action.yml | 4 ++-- .github/workflows/on-tag.yml | 2 +- .github/workflows/reusable-upload-recipe.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/actions/generate-version/action.yml b/.github/actions/generate-version/action.yml index 6b84aac2f3..8edb7920c6 100644 --- a/.github/actions/generate-version/action.yml +++ b/.github/actions/generate-version/action.yml @@ -11,7 +11,7 @@ runs: steps: # When a tag is pushed, the version is used as-is. - name: Generate version for tag event - if: ${{ github.event_name == 'tag' }} + if: ${{ startsWith(github.ref, 'refs/tags/') }} shell: bash env: VERSION: ${{ github.ref_name }} @@ -22,7 +22,7 @@ runs: # We use a plus sign instead of a hyphen because Conan recipe versions do # not support two hyphens. - name: Generate version for non-tag event - if: ${{ github.event_name != 'tag' }} + if: ${{ !startsWith(github.ref, 'refs/tags/') }} shell: bash run: | echo 'Extracting version from BuildInfo.cpp.' diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml index af3ea4309e..e570a0e119 100644 --- a/.github/workflows/on-tag.yml +++ b/.github/workflows/on-tag.yml @@ -5,7 +5,7 @@ name: Tag on: push: tags: - - "v*" + - "[0-9]+.[0-9]+.[0-9]*" concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/reusable-upload-recipe.yml b/.github/workflows/reusable-upload-recipe.yml index 178dd65b8e..d3fe0f356b 100644 --- a/.github/workflows/reusable-upload-recipe.yml +++ b/.github/workflows/reusable-upload-recipe.yml @@ -89,10 +89,10 @@ jobs: conan export . --version=rc conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc - # When this workflow is triggered by a tag event, it will always be when tagging a final + # When this workflow is triggered by a push event, it will always be when tagging a final # release, see on-tag.yml. - name: Upload Conan recipe (release) - if: ${{ github.event_name == 'tag' }} + if: ${{ startsWith(github.ref, 'refs/tags/') }} env: REMOTE_NAME: ${{ inputs.remote_name }} run: | From 9316da784a6290447a9164209e4440743210ab0f Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Thu, 19 Mar 2026 17:29:22 +0000 Subject: [PATCH 07/16] ci: Update XRPLF/actions (#6594) --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/publish-docs.yml | 2 +- .github/workflows/reusable-build-test-config.yml | 2 +- .github/workflows/reusable-clang-tidy-files.yml | 2 +- .github/workflows/upload-conan-deps.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8600429a6b..5cc99d1804 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -14,7 +14,7 @@ on: jobs: # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. run-hooks: - uses: XRPLF/actions/.github/workflows/pre-commit.yml@44856eb0d6ecb7d376370244324ab3dc8b863bad + uses: XRPLF/actions/.github/workflows/pre-commit.yml@e7896f15cc60d0da1a272c77ee5c4026b424f9c7 with: runs_on: ubuntu-latest container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }' diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index d4abd74363..4b840405bb 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -48,7 +48,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d + uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e with: enable_ccache: false diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 6e7a093b96..02a47e169d 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -107,7 +107,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d + uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e with: enable_ccache: ${{ inputs.ccache_enabled }} diff --git a/.github/workflows/reusable-clang-tidy-files.yml b/.github/workflows/reusable-clang-tidy-files.yml index 129726ec8f..5d3230f7d1 100644 --- a/.github/workflows/reusable-clang-tidy-files.yml +++ b/.github/workflows/reusable-clang-tidy-files.yml @@ -35,7 +35,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d + uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e with: enable_ccache: false diff --git a/.github/workflows/upload-conan-deps.yml b/.github/workflows/upload-conan-deps.yml index d0fea4b8ae..832e455453 100644 --- a/.github/workflows/upload-conan-deps.yml +++ b/.github/workflows/upload-conan-deps.yml @@ -70,7 +70,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d + uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e with: enable_ccache: false From fd28656ded6d7d23d650c1b50f7b7918bcd4434a Mon Sep 17 00:00:00 2001 From: Bart Date: Thu, 19 Mar 2026 13:38:09 -0400 Subject: [PATCH 08/16] ci: Check for signed commits in PR (#6559) Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com> --- .github/workflows/check-pr-commits.yml | 13 +++++++++++++ .github/workflows/check-pr-title.yml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/check-pr-commits.yml diff --git a/.github/workflows/check-pr-commits.yml b/.github/workflows/check-pr-commits.yml new file mode 100644 index 0000000000..07c62c9ff5 --- /dev/null +++ b/.github/workflows/check-pr-commits.yml @@ -0,0 +1,13 @@ +name: Check PR commits + +on: + pull_request: + +# The action needs to have write permissions to post comments on the PR. +permissions: + contents: read + pull-requests: write + +jobs: + check_commits: + uses: XRPLF/actions/.github/workflows/check-pr-commits.yml@481048b78b94ac3343d1292b4ef125a813879f2b diff --git a/.github/workflows/check-pr-title.yml b/.github/workflows/check-pr-title.yml index 1181ca586f..fc03cdf8e1 100644 --- a/.github/workflows/check-pr-title.yml +++ b/.github/workflows/check-pr-title.yml @@ -11,4 +11,4 @@ on: jobs: check_title: if: ${{ github.event.pull_request.draft != true }} - uses: XRPLF/actions/.github/workflows/check-pr-title.yml@f9c2b57a7ac30d70555b5de6e627005f62e933f3 + uses: XRPLF/actions/.github/workflows/check-pr-title.yml@e2c7f400d1e85ae65dad552fd425169fbacca4a3 From 762922a07f0a14cc834ab78b085854c019586fad Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Thu, 19 Mar 2026 21:20:56 +0000 Subject: [PATCH 09/16] chore: Don't allow files more than 400kb to be added to the repo (#6597) --- .pre-commit-config.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0fcd8ca75d..59d42ccebc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,12 +13,11 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: + - id: check-added-large-files + args: [--maxkb=400, --enforce-all] - id: trailing-whitespace - exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - id: end-of-file-fixer - exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - id: mixed-line-ending - exclude: ^include/xrpl/protocol_autogen/(transactions|ledger_entries)/ - id: check-merge-conflict args: [--assume-in-merge] From cf2eb149eed4ce1f449a4607f7b9106b3b780ac2 Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Thu, 19 Mar 2026 22:48:20 +0000 Subject: [PATCH 10/16] fix: Update `.git-blame-ignore-revs` (#6577) --- .git-blame-ignore-revs | 87 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index cf50d48f95..0cf704b051 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,16 +1,79 @@ # This feature requires Git >= 2.24 # To use it by default in git blame: # git config blame.ignoreRevsFile .git-blame-ignore-revs -50760c693510894ca368e90369b0cc2dabfd07f3 -e2384885f5f630c8f0ffe4bf21a169b433a16858 -241b9ddde9e11beb7480600fd5ed90e1ef109b21 -760f16f56835663d9286bd29294d074de26a7ba6 -0eebe6a5f4246fced516d52b83ec4e7f47373edd -2189cc950c0cebb89e4e2fa3b2d8817205bf7cef -b9d007813378ad0ff45660dc07285b823c7e9855 -fe9a5365b8a52d4acc42eb27369247e6f238a4f9 -9a93577314e6a8d4b4a8368cc9d2b15a5d8303e8 -552377c76f55b403a1c876df873a23d780fcc81c -97f0747e103f13e26e45b731731059b32f7679ac -b13370ac0d207217354f1fc1c29aef87769fb8a1 + +# This file is sorted in reverse chronological order, with the most recent commits at the top. +# The commits listed here are ignored by git blame, which is useful for formatting-only commits that would otherwise obscure the history of changes to a file. + +# refactor: Enable remaining clang-tidy `cppcoreguidelines` checks (#6538) +72f4cb097f626b08b02fc3efcb4aa11cb2e7adb8 +# refactor: Rename system name from 'ripple' to 'xrpld' (#6347) +ffea3977f0b771fe8e43a8f74e4d393d63a7afd8 +# refactor: Update transaction folder structure (#6483) +5865bd017f777491b4a956f9210be0c4161f5442 +# chore: Use gersemi instead of ancient cmake-format (#6486) +0c74270b055133a57a497b5c9fc5a75f7647b1f4 +# chore: Apply clang-format width 100 (#6387) +2c1fad102353e11293e3edde1c043224e7d3e983 +# chore: Set clang-format width to 100 in config file (#6387) +25cca465538a56cce501477f9e5e2c1c7ea2d84c +# chore: Set cmake-format width to 100 (#6386) +469ce9f291a4480c38d4ee3baca5136b2f053cd0 +# refactor: Modularize app/tx (#6228) +0976b2b68b64972af8e6e7c497900b5bce9fe22f +# chore: Update clang-format to 21.1.8 (#6352) +958d8f375453d80bb1aa4c293b5102c045a3e4b4 +# refactor: Replace include guards by '#pragma once' (#6322) +34ef577604782ca8d6e1c17df8bd7470990a52ff +# chore: Format all cmake files without comments (#6294) +fe9c8d568fcf6ac21483024e01f58962dd5c8260 +# chore: Add cmake-format pre-commit hook (#6279) +a0e09187b9370805d027c611a7e9ff5a0125282a +# chore: Set ColumnLimit to 120 in clang-format (#6288) +5f638f55536def0d88b970d1018a465a238e55f4 +# refactor: Fix typos in comments, configure cspell (#6164) +3c9f5b62525cb1d6ca1153eeb10433db7d7379fd +# refactor: Rename `rippled.cfg` to `xrpld.cfg` (#6098) +3d1b3a49b3601a0a7037fa0b19d5df7b5e0e2fc1 +# refactor: Rename `ripple` namespace to `xrpl` (#5982) +1eb0fdac6543706b4b9ddca57fd4102928a1f871 +# refactor: Rename `rippled` binary to `xrpld` (#5983) +9eb84a561ef8bb066d89f098bd9b4ac71baed67c +# refactor: Replaces secp256k1 source by Conan package (#6089) +813bc4d9491b078bb950f8255f93b02f71320478 +# refactor: Remove unnecessary copyright notices already covered by LICENSE.md (#5929) +1d42c4f6de6bf01d1286fc7459b17a37a5189e88 +# refactor: Rename `RIPPLE_` and `RIPPLED_` definitions to `XRPL_` (#5821) +ada83564d894829424b0f4d922b0e737e07abbf7 +# refactor: Modularize shamap and nodestore (#5668) +8eb233c2ea8ad5a159be73b77f0f5e1496d547ac +# refactor: Modularise ledger (#5493) +dc8b37a52448b005153c13a7f046ad494128cf94 +# chore: Update clang-format and prettier with pre-commit (#5709) +c14ce956adeabe476ad73c18d73103f347c9c613 +# chore: Fix file formatting (#5718) 896b8c3b54a22b0497cb0d1ce95e1095f9a227ce +# chore: Reverts formatting changes to external files, adds formatting changes to proto files (#5711) +b13370ac0d207217354f1fc1c29aef87769fb8a1 +# chore: Run prettier on all files (#5657) +97f0747e103f13e26e45b731731059b32f7679ac +# Reformat code with clang-format-18 +552377c76f55b403a1c876df873a23d780fcc81c +# Recompute loops (#4997) +d028005aa6319338b0adae1aebf8abe113162960 +# Rewrite includes (#4997) +1d23148e6dd53957fcb6205c07a5c6cd7b64d50c +# Rearrange sources (#4997) +e416ee72ca26fa0c09d2aee1b68bdfb2b7046eed +# Move CMake directory (#4997) +2e902dee53aab2a8f27f32971047bb81e022f94f +# Rewrite includes +0eebe6a5f4246fced516d52b83ec4e7f47373edd +# Format formerly .hpp files +760f16f56835663d9286bd29294d074de26a7ba6 +# Rename .hpp to .h +241b9ddde9e11beb7480600fd5ed90e1ef109b21 +# Consolidate external libraries +e2384885f5f630c8f0ffe4bf21a169b433a16858 +# Format first-party source according to .clang-format +50760c693510894ca368e90369b0cc2dabfd07f3 From be1cc48d84142e43f7a831165be43bc1865adad3 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sun, 22 Mar 2026 11:08:18 -0700 Subject: [PATCH 11/16] fix: Assorted Oracle fixes (#6570) --- src/libxrpl/tx/transactors/oracle/OracleSet.cpp | 2 +- src/xrpld/rpc/handlers/GetAggregatePrice.cpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libxrpl/tx/transactors/oracle/OracleSet.cpp b/src/libxrpl/tx/transactors/oracle/OracleSet.cpp index f0fc114d7f..6b21df4d2a 100644 --- a/src/libxrpl/tx/transactors/oracle/OracleSet.cpp +++ b/src/libxrpl/tx/transactors/oracle/OracleSet.cpp @@ -98,7 +98,7 @@ OracleSet::preclaim(PreclaimContext const& ctx) return !v || *v == (*sle)[field]; }; - std::uint32_t adjustReserve = 0; + std::int8_t adjustReserve = 0; if (sle) { // update diff --git a/src/xrpld/rpc/handlers/GetAggregatePrice.cpp b/src/xrpld/rpc/handlers/GetAggregatePrice.cpp index 4fc8e360fc..cf327258a3 100644 --- a/src/xrpld/rpc/handlers/GetAggregatePrice.cpp +++ b/src/xrpld/rpc/handlers/GetAggregatePrice.cpp @@ -218,6 +218,12 @@ doGetAggregatePrice(RPC::JsonContext& context) return result; } + // Get the ledger + std::shared_ptr ledger; + result = RPC::lookupLedger(ledger, context); + if (!ledger) + return result; // LCOV_EXCL_LINE + // Collect the dataset into bimap keyed by lastUpdateTime and // STAmount (Number is int64 and price is uint64) Prices prices; @@ -238,11 +244,6 @@ doGetAggregatePrice(RPC::JsonContext& context) return result; } - std::shared_ptr ledger; - result = RPC::lookupLedger(ledger, context); - if (!ledger) - return result; // LCOV_EXCL_LINE - auto const sle = ledger->read(keylet::oracle(*account, *documentID)); iteratePriceData(context, sle, [&](STObject const& node) { auto const& series = node.getFieldArray(sfPriceDataSeries); @@ -284,8 +285,8 @@ doGetAggregatePrice(RPC::JsonContext& context) if (auto const threshold = std::get(timeThreshold)) { // threshold defines an acceptable range {max,min} of lastUpdateTime as - // {latestTime, latestTime - threshold}, the prices with lastUpdateTime - // greater than (latestTime - threshold) are erased. + // {latestTime, latestTime - threshold}. Prices with lastUpdateTime + // less than (latestTime - threshold) are erased (outdated prices). auto const oldestTime = prices.left.rbegin()->first; auto const upperBound = latestTime > threshold ? (latestTime - threshold) : oldestTime; if (upperBound > oldestTime) From c463d0ff06d18c55d8f3982597667d29fd6f6166 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 10:04:22 -0400 Subject: [PATCH 12/16] ci: [DEPENDABOT] bump codecov/codecov-action from 5.5.2 to 5.5.3 (#6615) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/reusable-build-test-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 02a47e169d..1cc768f9fa 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -298,7 +298,7 @@ jobs: - name: Upload coverage report if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 with: disable_search: true disable_telem: true From e0dbe9037086248dc2a5b99511953a6677fcfc6b Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 23 Mar 2026 08:39:58 -0700 Subject: [PATCH 13/16] refactor: Move ledger entry helper functions from View.h/View.cpp to dedicated helper files (#6453) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- include/xrpl/ledger/Credit.h | 43 - include/xrpl/ledger/View.h | 876 +---- .../xrpl/ledger/helpers/AccountRootHelpers.h | 112 + .../ledger/{ => helpers}/CredentialHelpers.h | 0 .../xrpl/ledger/helpers/DirectoryHelpers.h | 223 ++ include/xrpl/ledger/helpers/MPTokenHelpers.h | 160 + include/xrpl/ledger/helpers/OfferHelpers.h | 28 + .../xrpl/ledger/helpers/RippleStateHelpers.h | 255 ++ include/xrpl/ledger/helpers/TokenHelpers.h | 286 ++ include/xrpl/ledger/helpers/VaultHelpers.h | 81 + include/xrpl/tx/paths/detail/StrandFlow.h | 3 +- src/libxrpl/ledger/Credit.cpp | 60 - src/libxrpl/ledger/View.cpp | 3212 +---------------- .../ledger/helpers/AccountRootHelpers.cpp | 247 ++ .../{ => helpers}/CredentialHelpers.cpp | 4 +- .../ledger/helpers/DirectoryHelpers.cpp | 177 + src/libxrpl/ledger/helpers/MPTokenHelpers.cpp | 766 ++++ src/libxrpl/ledger/helpers/OfferHelpers.cpp | 58 + .../ledger/helpers/RippleStateHelpers.cpp | 759 ++++ src/libxrpl/ledger/helpers/TokenHelpers.cpp | 1392 +++++++ src/libxrpl/ledger/helpers/VaultHelpers.cpp | 112 + src/libxrpl/tx/Transactor.cpp | 2 +- .../PermissionedDomainInvariant.cpp | 2 +- src/libxrpl/tx/paths/Flow.cpp | 2 +- .../tx/transactors/account/AccountDelete.cpp | 2 +- .../credentials/CredentialAccept.cpp | 2 +- .../credentials/CredentialCreate.cpp | 2 +- .../credentials/CredentialDelete.cpp | 2 +- .../dex/PermissionedDEXHelpers.cpp | 2 +- .../tx/transactors/escrow/EscrowFinish.cpp | 2 +- .../lending/LoanBrokerCoverWithdraw.cpp | 2 +- .../tx/transactors/payment/DepositPreauth.cpp | 2 +- .../tx/transactors/payment/Payment.cpp | 2 +- .../payment_channel/PaymentChannelClaim.cpp | 2 +- .../PermissionedDomainSet.cpp | 2 +- .../tx/transactors/vault/VaultDeposit.cpp | 2 +- .../tx/transactors/vault/VaultWithdraw.cpp | 2 +- src/test/app/Credentials_test.cpp | 2 +- src/xrpld/app/paths/detail/DirectStep.cpp | 2 +- .../app/paths/detail/XRPEndpointStep.cpp | 2 +- src/xrpld/rpc/handlers/DepositAuthorized.cpp | 2 +- src/xrpld/rpc/handlers/LedgerEntry.cpp | 2 +- 42 files changed, 4692 insertions(+), 4204 deletions(-) delete mode 100644 include/xrpl/ledger/Credit.h create mode 100644 include/xrpl/ledger/helpers/AccountRootHelpers.h rename include/xrpl/ledger/{ => helpers}/CredentialHelpers.h (100%) create mode 100644 include/xrpl/ledger/helpers/DirectoryHelpers.h create mode 100644 include/xrpl/ledger/helpers/MPTokenHelpers.h create mode 100644 include/xrpl/ledger/helpers/OfferHelpers.h create mode 100644 include/xrpl/ledger/helpers/RippleStateHelpers.h create mode 100644 include/xrpl/ledger/helpers/TokenHelpers.h create mode 100644 include/xrpl/ledger/helpers/VaultHelpers.h delete mode 100644 src/libxrpl/ledger/Credit.cpp create mode 100644 src/libxrpl/ledger/helpers/AccountRootHelpers.cpp rename src/libxrpl/ledger/{ => helpers}/CredentialHelpers.cpp (99%) create mode 100644 src/libxrpl/ledger/helpers/DirectoryHelpers.cpp create mode 100644 src/libxrpl/ledger/helpers/MPTokenHelpers.cpp create mode 100644 src/libxrpl/ledger/helpers/OfferHelpers.cpp create mode 100644 src/libxrpl/ledger/helpers/RippleStateHelpers.cpp create mode 100644 src/libxrpl/ledger/helpers/TokenHelpers.cpp create mode 100644 src/libxrpl/ledger/helpers/VaultHelpers.cpp diff --git a/include/xrpl/ledger/Credit.h b/include/xrpl/ledger/Credit.h deleted file mode 100644 index 770b82a650..0000000000 --- a/include/xrpl/ledger/Credit.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace xrpl { - -/** Calculate the maximum amount of IOUs that an account can hold - @param ledger the ledger to check against. - @param account the account of interest. - @param issuer the issuer of the IOU. - @param currency the IOU to check. - @return The maximum amount that can be held. -*/ -/** @{ */ -STAmount -creditLimit( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency); - -IOUAmount -creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur); -/** @} */ - -/** Returns the amount of IOUs issued by issuer that are held by an account - @param ledger the ledger to check against. - @param account the account of interest. - @param issuer the issuer of the IOU. - @param currency the IOU to check. -*/ -/** @{ */ -STAmount -creditBalance( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency); -/** @} */ - -} // namespace xrpl diff --git a/include/xrpl/ledger/View.h b/include/xrpl/ledger/View.h index cd23cf4978..2ea38c5b8b 100644 --- a/include/xrpl/ledger/View.h +++ b/include/xrpl/ledger/View.h @@ -4,6 +4,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -21,7 +28,6 @@ namespace xrpl { -enum class WaiveTransferFee : bool { No = false, Yes }; enum class SkipEntry : bool { No = false, Yes }; //------------------------------------------------------------------------------ @@ -54,24 +60,6 @@ enum class SkipEntry : bool { No = false, Yes }; [[nodiscard]] bool hasExpired(ReadView const& view, std::optional const& exp); -/** Controls the treatment of frozen account balances */ -enum FreezeHandling { fhIGNORE_FREEZE, fhZERO_IF_FROZEN }; - -/** Controls the treatment of unauthorized MPT balances */ -enum AuthHandling { ahIGNORE_AUTH, ahZERO_IF_UNAUTHORIZED }; - -/** Controls whether to include the account's full spendable balance */ -enum SpendableHandling { shSIMPLE_BALANCE, shFULL_BALANCE }; - -[[nodiscard]] bool -isGlobalFrozen(ReadView const& view, AccountID const& issuer); - -[[nodiscard]] bool -isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue); - -[[nodiscard]] bool -isGlobalFrozen(ReadView const& view, Asset const& asset); - // Note, depth parameter is used to limit the recursion depth [[nodiscard]] bool isVaultPseudoAccountFrozen( @@ -80,175 +68,6 @@ isVaultPseudoAccountFrozen( MPTIssue const& mptShare, int depth); -[[nodiscard]] bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); - -[[nodiscard]] inline bool -isIndividualFrozen(ReadView const& view, AccountID const& account, Issue const& issue) -{ - return isIndividualFrozen(view, account, issue.currency, issue.account); -} - -[[nodiscard]] bool -isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue); - -[[nodiscard]] inline bool -isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset) -{ - return std::visit( - [&](auto const& issue) { return isIndividualFrozen(view, account, issue); }, asset.value()); -} - -[[nodiscard]] bool -isFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); - -[[nodiscard]] inline bool -isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int = 0 /*ignored*/) -{ - return isFrozen(view, account, issue.currency, issue.account); -} - -[[nodiscard]] bool -isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0); - -/** - * isFrozen check is recursive for MPT shares in a vault, descending to - * assets in the vault, up to maxAssetCheckDepth recursion depth. This is - * purely defensive, as we currently do not allow such vaults to be created. - */ -[[nodiscard]] inline bool -isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0) -{ - return std::visit( - [&](auto const& issue) { return isFrozen(view, account, issue, depth); }, asset.value()); -} - -[[nodiscard]] inline TER -checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue) -{ - return isFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS; -} - -[[nodiscard]] inline TER -checkFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) -{ - return isFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; -} - -[[nodiscard]] inline TER -checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset) -{ - return std::visit( - [&](auto const& issue) { return checkFrozen(view, account, issue); }, asset.value()); -} - -[[nodiscard]] bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - MPTIssue const& mptIssue, - int depth = 0); - -[[nodiscard]] inline bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - Issue const& issue) -{ - for (auto const& account : accounts) - { - if (isFrozen(view, account, issue.currency, issue.account)) - return true; - } - return false; -} - -[[nodiscard]] inline bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - Asset const& asset, - int depth = 0) -{ - return std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - return isAnyFrozen(view, accounts, issue); - else - return isAnyFrozen(view, accounts, issue, depth); - }, - asset.value()); -} - -[[nodiscard]] bool -isDeepFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer); - -[[nodiscard]] inline bool -isDeepFrozen( - ReadView const& view, - AccountID const& account, - Issue const& issue, - int = 0 /*ignored*/) -{ - return isDeepFrozen(view, account, issue.currency, issue.account); -} - -[[nodiscard]] inline bool -isDeepFrozen( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue, - int depth = 0) -{ - // Unlike IOUs, frozen / locked MPTs are not allowed to send or receive - // funds, so checking "deep frozen" is the same as checking "frozen". - return isFrozen(view, account, mptIssue, depth); -} - -/** - * isFrozen check is recursive for MPT shares in a vault, descending to - * assets in the vault, up to maxAssetCheckDepth recursion depth. This is - * purely defensive, as we currently do not allow such vaults to be created. - */ -[[nodiscard]] inline bool -isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0) -{ - return std::visit( - [&](auto const& issue) { return isDeepFrozen(view, account, issue, depth); }, - asset.value()); -} - -[[nodiscard]] inline TER -checkDeepFrozen(ReadView const& view, AccountID const& account, Issue const& issue) -{ - return isDeepFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS; -} - -[[nodiscard]] inline TER -checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) -{ - return isDeepFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; -} - -[[nodiscard]] inline TER -checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset) -{ - return std::visit( - [&](auto const& issue) { return checkDeepFrozen(view, account, issue); }, asset.value()); -} - [[nodiscard]] bool isLPTokenFrozen( ReadView const& view, @@ -256,159 +75,6 @@ isLPTokenFrozen( Issue const& asset, Issue const& asset2); -// Returns the amount an account can spend. -// -// If shSIMPLE_BALANCE is specified, this is the amount the account can spend -// without going into debt. -// -// If shFULL_BALANCE is specified, this is the amount the account can spend -// total. Specifically: -// * The account can go into debt if using a trust line, and the other side has -// a non-zero limit. -// * If the account is the asset issuer the limit is defined by the asset / -// issuance. -// -// <-- saAmount: amount of currency held by account. May be negative. -[[nodiscard]] STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer, - FreezeHandling zeroIfFrozen, - beast::Journal j, - SpendableHandling includeFullBalance = shSIMPLE_BALANCE); - -[[nodiscard]] STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - Issue const& issue, - FreezeHandling zeroIfFrozen, - beast::Journal j, - SpendableHandling includeFullBalance = shSIMPLE_BALANCE); - -[[nodiscard]] STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue, - FreezeHandling zeroIfFrozen, - AuthHandling zeroIfUnauthorized, - beast::Journal j, - SpendableHandling includeFullBalance = shSIMPLE_BALANCE); - -[[nodiscard]] STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - Asset const& asset, - FreezeHandling zeroIfFrozen, - AuthHandling zeroIfUnauthorized, - beast::Journal j, - SpendableHandling includeFullBalance = shSIMPLE_BALANCE); - -// Returns the amount an account can spend of the currency type saDefault, or -// returns saDefault if this account is the issuer of the currency in -// question. Should be used in favor of accountHolds when questioning how much -// an account can spend while also allowing currency issuers to spend -// unlimited amounts of their own currency (since they can always issue more). -[[nodiscard]] STAmount -accountFunds( - ReadView const& view, - AccountID const& id, - STAmount const& saDefault, - FreezeHandling freezeHandling, - beast::Journal j); - -// Return the account's liquid (not reserved) XRP. Generally prefer -// calling accountHolds() over this interface. However, this interface -// allows the caller to temporarily adjust the owner count should that be -// necessary. -// -// @param ownerCountAdj positive to add to count, negative to reduce count. -[[nodiscard]] XRPAmount -xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j); - -/** Iterate all items in the given directory. */ -void -forEachItem( - ReadView const& view, - Keylet const& root, - std::function const&)> const& f); - -/** Iterate all items after an item in the given directory. - @param after The key of the item to start after - @param hint The directory page containing `after` - @param limit The maximum number of items to return - @return `false` if the iteration failed -*/ -bool -forEachItemAfter( - ReadView const& view, - Keylet const& root, - uint256 const& after, - std::uint64_t const hint, - unsigned int limit, - std::function const&)> const& f); - -/** Iterate all items in an account's owner directory. */ -inline void -forEachItem( - ReadView const& view, - AccountID const& id, - std::function const&)> const& f) -{ - return forEachItem(view, keylet::ownerDir(id), f); -} - -/** Iterate all items after an item in an owner directory. - @param after The key of the item to start after - @param hint The directory page containing `after` - @param limit The maximum number of items to return - @return `false` if the iteration failed -*/ -inline bool -forEachItemAfter( - ReadView const& view, - AccountID const& id, - uint256 const& after, - std::uint64_t const hint, - unsigned int limit, - std::function const&)> const& f) -{ - return forEachItemAfter(view, keylet::ownerDir(id), after, hint, limit, f); -} - -/** Returns IOU issuer transfer fee as Rate. Rate specifies - * the fee as fractions of 1 billion. For example, 1% transfer rate - * is represented as 1,010,000,000. - * @param issuer The IOU issuer - */ -[[nodiscard]] Rate -transferRate(ReadView const& view, AccountID const& issuer); - -/** Returns MPT transfer fee as Rate. Rate specifies - * the fee as fractions of 1 billion. For example, 1% transfer rate - * is represented as 1,010,000,000. - * @param issuanceID MPTokenIssuanceID of MPTTokenIssuance object - */ -[[nodiscard]] Rate -transferRate(ReadView const& view, MPTID const& issuanceID); - -/** Returns the transfer fee as Rate based on the type of token - * @param view The ledger view - * @param amount The amount to transfer - */ -[[nodiscard]] Rate -transferRate(ReadView const& view, STAmount const& amount); - -/** Returns `true` if the directory is empty - @param key The key of the directory -*/ -[[nodiscard]] bool -dirIsEmpty(ReadView const& view, Keylet const& k); - // Return the list of enabled amendments [[nodiscard]] std::set getEnabledAmendments(ReadView const& view); @@ -474,81 +140,6 @@ areCompatible( // //------------------------------------------------------------------------------ -/** Adjust the owner count up or down. */ -void -adjustOwnerCount( - ApplyView& view, - std::shared_ptr const& sle, - std::int32_t amount, - beast::Journal j); - -/** @{ */ -/** Returns the first entry in the directory, advancing the index - - @deprecated These are legacy function that are considered deprecated - and will soon be replaced with an iterator-based model - that is easier to use. You should not use them in new code. - - @param view The view against which to operate - @param root The root (i.e. first page) of the directory to iterate - @param page The current page - @param index The index inside the current page - @param entry The entry at the current index - - @return true if the directory isn't empty; false otherwise - */ -bool -cdirFirst( - ReadView const& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry); - -bool -dirFirst( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry); -/** @} */ - -/** @{ */ -/** Returns the next entry in the directory, advancing the index - - @deprecated These are legacy function that are considered deprecated - and will soon be replaced with an iterator-based model - that is easier to use. You should not use them in new code. - - @param view The view against which to operate - @param root The root (i.e. first page) of the directory to iterate - @param page The current page - @param index The index inside the current page - @param entry The entry at the current index - - @return true if the directory isn't empty; false otherwise - */ -bool -cdirNext( - ReadView const& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry); - -bool -dirNext( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry); -/** @} */ - -[[nodiscard]] std::function -describeOwnerDir(AccountID const& account); - [[nodiscard]] TER dirLink( ApplyView& view, @@ -556,63 +147,6 @@ dirLink( std::shared_ptr& object, SF_UINT64 const& node = sfOwnerNode); -AccountID -pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); - -/** - * - * Create pseudo-account, storing pseudoOwnerKey into ownerField. - * - * The list of valid ownerField is maintained in View.cpp and the caller to - * this function must perform necessary amendment check(s) before using a - * field. The amendment check is **not** performed in createPseudoAccount. - */ -[[nodiscard]] Expected, TER> -createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField); - -// Returns true if and only if sleAcct is a pseudo-account or specific -// pseudo-accounts in pseudoFieldFilter. -// -// Returns false if sleAcct is -// * NOT a pseudo-account OR -// * NOT a ltACCOUNT_ROOT OR -// * null pointer -[[nodiscard]] bool -isPseudoAccount( - std::shared_ptr sleAcct, - std::set const& pseudoFieldFilter = {}); - -// Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if -// set -// Pseudo-account designator fields MUST be maintained by including the -// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to -// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated, -// since a non-active amendment will not set any field, by definition. -// Specific properties of a pseudo-account are NOT checked here, that's what -// InvariantCheck is for. -[[nodiscard]] std::vector const& -getPseudoAccountFields(); - -[[nodiscard]] inline bool -isPseudoAccount( - ReadView const& view, - AccountID const& accountId, - std::set const& pseudoFieldFilter = {}) -{ - return isPseudoAccount(view.read(keylet::account(accountId)), pseudoFieldFilter); -} - -[[nodiscard]] TER -canAddHolding(ReadView const& view, Asset const& asset); - -/** Validates that the destination SLE and tag are valid - - - Checks that the SLE is not null. - - If the SLE requires a destination tag, checks that there is a tag. -*/ -[[nodiscard]] TER -checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag); - /** Checks that can withdraw funds from an object to itself or a destination. * * The receiver may be either the submitting account (sfAccount) or a different @@ -686,351 +220,6 @@ doWithdraw( STAmount const& amount, beast::Journal j); -/// Any transactors that call addEmptyHolding() in doApply must call -/// canAddHolding() in preflight with the same View and Asset -[[nodiscard]] TER -addEmptyHolding( - ApplyView& view, - AccountID const& accountID, - XRPAmount priorBalance, - Issue const& issue, - beast::Journal journal); - -[[nodiscard]] TER -addEmptyHolding( - ApplyView& view, - AccountID const& accountID, - XRPAmount priorBalance, - MPTIssue const& mptIssue, - beast::Journal journal); - -[[nodiscard]] inline TER -addEmptyHolding( - ApplyView& view, - AccountID const& accountID, - XRPAmount priorBalance, - Asset const& asset, - beast::Journal journal) -{ - return std::visit( - [&](TIss const& issue) -> TER { - return addEmptyHolding(view, accountID, priorBalance, issue, journal); - }, - asset.value()); -} - -[[nodiscard]] TER -authorizeMPToken( - ApplyView& view, - XRPAmount const& priorBalance, - MPTID const& mptIssuanceID, - AccountID const& account, - beast::Journal journal, - std::uint32_t flags = 0, - std::optional holderID = std::nullopt); - -// VFALCO NOTE Both STAmount parameters should just -// be "Amount", a unit-less number. -// -/** Create a trust line - - This can set an initial balance. -*/ -[[nodiscard]] TER -trustCreate( - ApplyView& view, - bool const bSrcHigh, - AccountID const& uSrcAccountID, - AccountID const& uDstAccountID, - uint256 const& uIndex, // --> ripple state entry - SLE::ref sleAccount, // --> the account being set. - bool const bAuth, // --> authorize account. - bool const bNoRipple, // --> others cannot ripple through - bool const bFreeze, // --> funds cannot leave - bool bDeepFreeze, // --> can neither receive nor send funds - STAmount const& saBalance, // --> balance of account being set. - // Issuer should be noAccount() - STAmount const& saLimit, // --> limit for account being set. - // Issuer should be the account being set. - std::uint32_t uSrcQualityIn, - std::uint32_t uSrcQualityOut, - beast::Journal j); - -[[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - Issue const& issue, - beast::Journal journal); - -[[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - MPTIssue const& mptIssue, - beast::Journal journal); - -[[nodiscard]] inline TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - Asset const& asset, - beast::Journal journal) -{ - return std::visit( - [&](TIss const& issue) -> TER { - return removeEmptyHolding(view, accountID, issue, journal); - }, - asset.value()); -} - -[[nodiscard]] TER -trustDelete( - ApplyView& view, - std::shared_ptr const& sleRippleState, - AccountID const& uLowAccountID, - AccountID const& uHighAccountID, - beast::Journal j); - -/** Delete an offer. - - Requirements: - The passed `sle` be obtained from a prior - call to view.peek() -*/ -// [[nodiscard]] // nodiscard commented out so Flow, BookTip and others compile. -TER -offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j); - -//------------------------------------------------------------------------------ - -// -// Money Transfers -// - -// Direct send w/o fees: -// - Redeeming IOUs and/or sending sender's own IOUs. -// - Create trust line of needed. -// --> bCheckIssuer : normally require issuer to be involved. -// [[nodiscard]] // nodiscard commented out so DirectStep.cpp compiles. - -/** Calls static rippleCreditIOU if saAmount represents Issue. - * Calls static rippleCreditMPT if saAmount represents MPTIssue. - */ -TER -rippleCredit( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - bool bCheckIssuer, - beast::Journal j); - -TER -rippleLockEscrowMPT( - ApplyView& view, - AccountID const& uGrantorID, - STAmount const& saAmount, - beast::Journal j); - -TER -rippleUnlockEscrowMPT( - ApplyView& view, - AccountID const& uGrantorID, - AccountID const& uGranteeID, - STAmount const& netAmount, - STAmount const& grossAmount, - beast::Journal j); - -/** Calls static accountSendIOU if saAmount represents Issue. - * Calls static accountSendMPT if saAmount represents MPTIssue. - */ -[[nodiscard]] TER -accountSend( - ApplyView& view, - AccountID const& from, - AccountID const& to, - STAmount const& saAmount, - beast::Journal j, - WaiveTransferFee waiveFee = WaiveTransferFee::No); - -using MultiplePaymentDestinations = std::vector>; -/** Like accountSend, except one account is sending multiple payments (with the - * same asset!) simultaneously - * - * Calls static accountSendMultiIOU if saAmount represents Issue. - * Calls static accountSendMultiMPT if saAmount represents MPTIssue. - */ -[[nodiscard]] TER -accountSendMulti( - ApplyView& view, - AccountID const& senderID, - Asset const& asset, - MultiplePaymentDestinations const& receivers, - beast::Journal j, - WaiveTransferFee waiveFee = WaiveTransferFee::No); - -[[nodiscard]] TER -issueIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j); - -[[nodiscard]] TER -redeemIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j); - -[[nodiscard]] TER -transferXRP( - ApplyView& view, - AccountID const& from, - AccountID const& to, - STAmount const& amount, - beast::Journal j); - -/* Check if MPToken (for MPT) or trust line (for IOU) exists: - * - StrongAuth - before checking if authorization is required - * - WeakAuth - * for MPT - after checking lsfMPTRequireAuth flag - * for IOU - do not check if trust line exists - * - Legacy - * for MPT - before checking lsfMPTRequireAuth flag i.e. same as StrongAuth - * for IOU - do not check if trust line exists i.e. same as WeakAuth - */ -enum class AuthType { StrongAuth, WeakAuth, Legacy }; - -/** Check if the account lacks required authorization. - * - * Return tecNO_AUTH or tecNO_LINE if it does - * and tesSUCCESS otherwise. - * - * If StrongAuth then return tecNO_LINE if the RippleState doesn't exist. Return - * tecNO_AUTH if lsfRequireAuth is set on the issuer's AccountRoot, and the - * RippleState does exist, and the RippleState is not authorized. - * - * If WeakAuth then return tecNO_AUTH if lsfRequireAuth is set, and the - * RippleState exists, and is not authorized. Return tecNO_LINE if - * lsfRequireAuth is set and the RippleState doesn't exist. Consequently, if - * WeakAuth and lsfRequireAuth is *not* set, this function will return - * tesSUCCESS even if RippleState does *not* exist. - * - * The default "Legacy" auth type is equivalent to WeakAuth. - */ -[[nodiscard]] TER -requireAuth( - ReadView const& view, - Issue const& issue, - AccountID const& account, - AuthType authType = AuthType::Legacy); - -/** Check if the account lacks required authorization. - * - * This will also check for expired credentials. If it is called directly - * from preclaim, the user should convert result tecEXPIRED to tesSUCCESS and - * proceed to also check permissions with enforceMPTokenAuthorization inside - * doApply. This will ensure that any expired credentials are deleted. - * - * requireAuth check is recursive for MPT shares in a vault, descending to - * assets in the vault, up to maxAssetCheckDepth recursion depth. This is - * purely defensive, as we currently do not allow such vaults to be created. - * - * If StrongAuth then return tecNO_AUTH if MPToken doesn't exist or - * lsfMPTRequireAuth is set and MPToken is not authorized. Vault and LoanBroker - * pseudo-accounts are implicitly authorized. - * - * If WeakAuth then return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken - * doesn't exist or is not authorized (explicitly or via credentials, if - * DomainID is set in MPTokenIssuance). Consequently, if WeakAuth and - * lsfMPTRequireAuth is *not* set, this function will return true even if - * MPToken does *not* exist. - * - * The default "Legacy" auth type is equivalent to StrongAuth. - */ -[[nodiscard]] TER -requireAuth( - ReadView const& view, - MPTIssue const& mptIssue, - AccountID const& account, - AuthType authType = AuthType::Legacy, - int depth = 0); - -[[nodiscard]] TER inline requireAuth( - ReadView const& view, - Asset const& asset, - AccountID const& account, - AuthType authType = AuthType::Legacy) -{ - return std::visit( - [&](TIss const& issue_) { - return requireAuth(view, issue_, account, authType); - }, - asset.value()); -} - -/** Enforce account has MPToken to match its authorization. - * - * Called from doApply - it will check for expired (and delete if found any) - * credentials matching DomainID set in MPTokenIssuance. Must be called if - * requireAuth(...MPTIssue...) returned tesSUCCESS or tecEXPIRED in preclaim, - * which implies that preclaim should replace `tecEXPIRED` with `tesSUCCESS` - * in order for the transactor to proceed to doApply. - * - * This function will create MPToken (if needed) on the basis of any - * non-expired credentials and will delete any expired credentials, indirectly - * via verifyValidDomain, as per DomainID (if set in MPTokenIssuance). - * - * The caller does NOT need to ensure that DomainID is actually set - this - * function handles gracefully both cases when DomainID is set and when not. - * - * The caller does NOT need to look for existing MPToken to match - * mptIssue/account - this function checks lsfMPTAuthorized of an existing - * MPToken iff DomainID is not set. - * - * Do not use for accounts which hold implied permission e.g. object owners or - * if MPTokenIssuance does not require authorization. In both cases use - * MPTokenAuthorize::authorize if MPToken does not yet exist. - */ -[[nodiscard]] TER -enforceMPTokenAuthorization( - ApplyView& view, - MPTID const& mptIssuanceID, - AccountID const& account, - XRPAmount const& priorBalance, - beast::Journal j); - -/** Check if the destination account is allowed - * to receive MPT. Return tecNO_AUTH if it doesn't - * and tesSUCCESS otherwise. - */ -[[nodiscard]] TER -canTransfer( - ReadView const& view, - MPTIssue const& mptIssue, - AccountID const& from, - AccountID const& to); - -[[nodiscard]] TER -canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to); - -[[nodiscard]] TER inline canTransfer( - ReadView const& view, - Asset const& asset, - AccountID const& from, - AccountID const& to) -{ - return std::visit( - [&](TIss const& issue) -> TER { - return canTransfer(view, issue, from, to); - }, - asset.value()); -} - /** Deleter function prototype. Returns the status of the entry deletion * (if should not be skipped) and if the entry should be skipped. The status * is always tesSUCCESS if the entry should be skipped. @@ -1052,57 +241,6 @@ cleanupOnAccountDelete( beast::Journal j, std::optional maxNodesToDelete = std::nullopt); -/** Delete trustline to AMM. The passed `sle` must be obtained from a prior - * call to view.peek(). Fail if neither side of the trustline is AMM or - * if ammAccountID is seated and is not one of the trustline's side. - */ -[[nodiscard]] TER -deleteAMMTrustLine( - ApplyView& view, - std::shared_ptr sleState, - std::optional const& ammAccountID, - beast::Journal j); - -// From the perspective of a vault, return the number of shares to give the -// depositor when they deposit a fixed amount of assets. Since shares are MPT -// this number is integral and always truncated in this calculation. -[[nodiscard]] std::optional -assetsToSharesDeposit( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& assets); - -// From the perspective of a vault, return the number of assets to take from -// depositor when they receive a fixed amount of shares. Note, since shares are -// MPT, they are always an integral number. -[[nodiscard]] std::optional -sharesToAssetsDeposit( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& shares); - -enum class TruncateShares : bool { no = false, yes = true }; - -// From the perspective of a vault, return the number of shares to demand from -// the depositor when they ask to withdraw a fixed amount of assets. Since -// shares are MPT this number is integral, and it will be rounded to nearest -// unless explicitly requested to be truncated instead. -[[nodiscard]] std::optional -assetsToSharesWithdraw( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& assets, - TruncateShares truncate = TruncateShares::no); - -// From the perspective of a vault, return the number of assets to give the -// depositor when they redeem a fixed amount of shares. Note, since shares are -// MPT, they are always an integral number. -[[nodiscard]] std::optional -sharesToAssetsWithdraw( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& shares); - /** Has the specified time passed? @param now the current time diff --git a/include/xrpl/ledger/helpers/AccountRootHelpers.h b/include/xrpl/ledger/helpers/AccountRootHelpers.h new file mode 100644 index 0000000000..353c27fe41 --- /dev/null +++ b/include/xrpl/ledger/helpers/AccountRootHelpers.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl { + +/** Check if the issuer has the global freeze flag set. + @param issuer The account to check + @return true if the account has global freeze set +*/ +[[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. +[[nodiscard]] XRPAmount +xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j); + +/** Adjust the owner count up or down. */ +void +adjustOwnerCount( + ApplyView& view, + std::shared_ptr const& sle, + std::int32_t amount, + beast::Journal j); + +/** Returns IOU issuer transfer fee as Rate. Rate specifies + * the fee as fractions of 1 billion. For example, 1% transfer rate + * is represented as 1,010,000,000. + * @param issuer The IOU issuer + */ +[[nodiscard]] Rate +transferRate(ReadView const& view, AccountID const& issuer); + +/** Generate a pseudo-account address from a pseudo owner key. + @param pseudoOwnerKey The key to generate the address from + @return The generated account ID +*/ +AccountID +pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); + +/** Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account + if set. + + The list is constructed during initialization and is const after that. + Pseudo-account designator fields MUST be maintained by including the + SField::sMD_PseudoAccount flag in the SField definition. +*/ +[[nodiscard]] std::vector const& +getPseudoAccountFields(); + +/** Returns true if and only if sleAcct is a pseudo-account or specific + pseudo-accounts in pseudoFieldFilter. + + Returns false if sleAcct is: + - NOT a pseudo-account OR + - NOT a ltACCOUNT_ROOT OR + - null pointer +*/ +[[nodiscard]] bool +isPseudoAccount( + std::shared_ptr sleAcct, + std::set const& pseudoFieldFilter = {}); + +/** Convenience overload that reads the account from the view. */ +[[nodiscard]] inline bool +isPseudoAccount( + ReadView const& view, + AccountID const& accountId, + std::set const& pseudoFieldFilter = {}) +{ + return isPseudoAccount(view.read(keylet::account(accountId)), pseudoFieldFilter); +} + +/** + * Create pseudo-account, storing pseudoOwnerKey into ownerField. + * + * The list of valid ownerField is maintained in AccountRootHelpers.cpp and + * the caller to this function must perform necessary amendment check(s) + * before using a field. The amendment check is **not** performed in + * createPseudoAccount. + */ +[[nodiscard]] Expected, TER> +createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField); + +/** Checks the destination and tag. + + - Checks that the SLE is not null. + - If the SLE requires a destination tag, checks that there is a tag. +*/ +[[nodiscard]] TER +checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag); + +} // namespace xrpl diff --git a/include/xrpl/ledger/CredentialHelpers.h b/include/xrpl/ledger/helpers/CredentialHelpers.h similarity index 100% rename from include/xrpl/ledger/CredentialHelpers.h rename to include/xrpl/ledger/helpers/CredentialHelpers.h diff --git a/include/xrpl/ledger/helpers/DirectoryHelpers.h b/include/xrpl/ledger/helpers/DirectoryHelpers.h new file mode 100644 index 0000000000..189dfcd263 --- /dev/null +++ b/include/xrpl/ledger/helpers/DirectoryHelpers.h @@ -0,0 +1,223 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl { + +namespace detail { + +template < + class V, + class N, + class = std::enable_if_t< + std::is_same_v, SLE> && std::is_base_of_v>> +bool +internalDirNext( + V& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry) +{ + auto const& svIndexes = page->getFieldV256(sfIndexes); + XRPL_ASSERT(index <= svIndexes.size(), "xrpl::detail::internalDirNext : index inside range"); + + if (index >= svIndexes.size()) + { + auto const next = page->getFieldU64(sfIndexNext); + + if (!next) + { + entry.zero(); + return false; + } + + if constexpr (std::is_const_v) + { + page = view.read(keylet::page(root, next)); + } + else + { + page = view.peek(keylet::page(root, next)); + } + + XRPL_ASSERT(page, "xrpl::detail::internalDirNext : non-null root"); + + if (!page) + return false; + + index = 0; + + return internalDirNext(view, root, page, index, entry); + } + + entry = svIndexes[index++]; + return true; +} + +template < + class V, + class N, + class = std::enable_if_t< + std::is_same_v, SLE> && std::is_base_of_v>> +bool +internalDirFirst( + V& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry) +{ + if constexpr (std::is_const_v) + { + page = view.read(keylet::page(root)); + } + else + { + page = view.peek(keylet::page(root)); + } + + if (!page) + return false; + + index = 0; + + return internalDirNext(view, root, page, index, entry); +} + +} // namespace detail + +/** @{ */ +/** Returns the first entry in the directory, advancing the index + + @deprecated These are legacy function that are considered deprecated + and will soon be replaced with an iterator-based model + that is easier to use. You should not use them in new code. + + @param view The view against which to operate + @param root The root (i.e. first page) of the directory to iterate + @param page The current page + @param index The index inside the current page + @param entry The entry at the current index + + @return true if the directory isn't empty; false otherwise + */ +bool +cdirFirst( + ReadView const& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry); + +bool +dirFirst( + ApplyView& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry); +/** @} */ + +/** @{ */ +/** Returns the next entry in the directory, advancing the index + + @deprecated These are legacy function that are considered deprecated + and will soon be replaced with an iterator-based model + that is easier to use. You should not use them in new code. + + @param view The view against which to operate + @param root The root (i.e. first page) of the directory to iterate + @param page The current page + @param index The index inside the current page + @param entry The entry at the current index + + @return true if the directory isn't empty; false otherwise + */ +bool +cdirNext( + ReadView const& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry); + +bool +dirNext( + ApplyView& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry); +/** @} */ + +/** Iterate all items in the given directory. */ +void +forEachItem( + ReadView const& view, + Keylet const& root, + std::function const&)> const& f); + +/** Iterate all items after an item in the given directory. + @param after The key of the item to start after + @param hint The directory page containing `after` + @param limit The maximum number of items to return + @return `false` if the iteration failed +*/ +bool +forEachItemAfter( + ReadView const& view, + Keylet const& root, + uint256 const& after, + std::uint64_t const hint, + unsigned int limit, + std::function const&)> const& f); + +/** Iterate all items in an account's owner directory. */ +inline void +forEachItem( + ReadView const& view, + AccountID const& id, + std::function const&)> const& f) +{ + return forEachItem(view, keylet::ownerDir(id), f); +} + +/** Iterate all items after an item in an owner directory. + @param after The key of the item to start after + @param hint The directory page containing `after` + @param limit The maximum number of items to return + @return `false` if the iteration failed +*/ +inline bool +forEachItemAfter( + ReadView const& view, + AccountID const& id, + uint256 const& after, + std::uint64_t const hint, + unsigned int limit, + std::function const&)> const& f) +{ + return forEachItemAfter(view, keylet::ownerDir(id), after, hint, limit, f); +} + +/** Returns `true` if the directory is empty + @param key The key of the directory +*/ +[[nodiscard]] bool +dirIsEmpty(ReadView const& view, Keylet const& k); + +/** Returns a function that sets the owner on a directory SLE */ +[[nodiscard]] std::function +describeOwnerDir(AccountID const& account); + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/MPTokenHelpers.h b/include/xrpl/ledger/helpers/MPTokenHelpers.h new file mode 100644 index 0000000000..ab487280b9 --- /dev/null +++ b/include/xrpl/ledger/helpers/MPTokenHelpers.h @@ -0,0 +1,160 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl { + +//------------------------------------------------------------------------------ +// +// Freeze checking (MPT-specific) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] bool +isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue); + +[[nodiscard]] bool +isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue); + +[[nodiscard]] bool +isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0); + +[[nodiscard]] bool +isAnyFrozen( + ReadView const& view, + std::initializer_list const& accounts, + MPTIssue const& mptIssue, + int depth = 0); + +//------------------------------------------------------------------------------ +// +// Transfer rate (MPT-specific) +// +//------------------------------------------------------------------------------ + +/** Returns MPT transfer fee as Rate. Rate specifies + * the fee as fractions of 1 billion. For example, 1% transfer rate + * is represented as 1,010,000,000. + * @param issuanceID MPTokenIssuanceID of MPTTokenIssuance object + */ +[[nodiscard]] Rate +transferRate(ReadView const& view, MPTID const& issuanceID); + +//------------------------------------------------------------------------------ +// +// Holding checks (MPT-specific) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +canAddHolding(ReadView const& view, MPTIssue const& mptIssue); + +//------------------------------------------------------------------------------ +// +// Authorization (MPT-specific) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +authorizeMPToken( + ApplyView& view, + XRPAmount const& priorBalance, + MPTID const& mptIssuanceID, + AccountID const& account, + beast::Journal journal, + std::uint32_t flags = 0, + std::optional holderID = std::nullopt); + +/** Check if the account lacks required authorization for MPT. + * + * requireAuth check is recursive for MPT shares in a vault, descending to + * assets in the vault, up to maxAssetCheckDepth recursion depth. This is + * purely defensive, as we currently do not allow such vaults to be created. + */ +[[nodiscard]] TER +requireAuth( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& account, + AuthType authType = AuthType::Legacy, + int depth = 0); + +/** Enforce account has MPToken to match its authorization. + * + * Called from doApply - it will check for expired (and delete if found any) + * credentials matching DomainID set in MPTokenIssuance. Must be called if + * requireAuth(...MPTIssue...) returned tesSUCCESS or tecEXPIRED in preclaim. + */ +[[nodiscard]] TER +enforceMPTokenAuthorization( + ApplyView& view, + MPTID const& mptIssuanceID, + AccountID const& account, + XRPAmount const& priorBalance, + beast::Journal j); + +/** Check if the destination account is allowed + * to receive MPT. Return tecNO_AUTH if it doesn't + * and tesSUCCESS otherwise. + */ +[[nodiscard]] TER +canTransfer( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& from, + AccountID const& to); + +//------------------------------------------------------------------------------ +// +// Empty holding operations (MPT-specific) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +addEmptyHolding( + ApplyView& view, + AccountID const& accountID, + XRPAmount priorBalance, + MPTIssue const& mptIssue, + beast::Journal journal); + +[[nodiscard]] TER +removeEmptyHolding( + ApplyView& view, + AccountID const& accountID, + MPTIssue const& mptIssue, + beast::Journal journal); + +//------------------------------------------------------------------------------ +// +// Escrow operations (MPT-specific) +// +//------------------------------------------------------------------------------ + +TER +rippleLockEscrowMPT( + ApplyView& view, + AccountID const& uGrantorID, + STAmount const& saAmount, + beast::Journal j); + +TER +rippleUnlockEscrowMPT( + ApplyView& view, + AccountID const& uGrantorID, + AccountID const& uGranteeID, + STAmount const& netAmount, + STAmount const& grossAmount, + beast::Journal j); + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/OfferHelpers.h b/include/xrpl/ledger/helpers/OfferHelpers.h new file mode 100644 index 0000000000..9096071811 --- /dev/null +++ b/include/xrpl/ledger/helpers/OfferHelpers.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace xrpl { + +/** Delete an offer. + + Requirements: + The offer must exist. + The caller must have already checked permissions. + + @param view The ApplyView to modify. + @param sle The offer to delete. + @param j Journal for logging. + + @return tesSUCCESS on success, otherwise an error code. +*/ +// [[nodiscard]] // nodiscard commented out so Flow, BookTip and others compile. +TER +offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j); + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/RippleStateHelpers.h b/include/xrpl/ledger/helpers/RippleStateHelpers.h new file mode 100644 index 0000000000..3feba59d1f --- /dev/null +++ b/include/xrpl/ledger/helpers/RippleStateHelpers.h @@ -0,0 +1,255 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// +// RippleState (Trustline) helpers +// +//------------------------------------------------------------------------------ + +namespace xrpl { + +//------------------------------------------------------------------------------ +// +// Credit functions (from Credit.h) +// +//------------------------------------------------------------------------------ + +/** Calculate the maximum amount of IOUs that an account can hold + @param view the ledger to check against. + @param account the account of interest. + @param issuer the issuer of the IOU. + @param currency the IOU to check. + @return The maximum amount that can be held. +*/ +/** @{ */ +STAmount +creditLimit( + ReadView const& view, + AccountID const& account, + AccountID const& issuer, + Currency const& currency); + +IOUAmount +creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur); +/** @} */ + +/** Returns the amount of IOUs issued by issuer that are held by an account + @param view the ledger to check against. + @param account the account of interest. + @param issuer the issuer of the IOU. + @param currency the IOU to check. +*/ +/** @{ */ +STAmount +creditBalance( + ReadView const& view, + AccountID const& account, + AccountID const& issuer, + Currency const& currency); +/** @} */ + +//------------------------------------------------------------------------------ +// +// Freeze checking (IOU-specific) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] bool +isIndividualFrozen( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer); + +[[nodiscard]] inline bool +isIndividualFrozen(ReadView const& view, AccountID const& account, Issue const& issue) +{ + return isIndividualFrozen(view, account, issue.currency, issue.account); +} + +[[nodiscard]] bool +isFrozen( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer); + +[[nodiscard]] inline bool +isFrozen(ReadView const& view, AccountID const& account, Issue const& issue) +{ + return isFrozen(view, account, issue.currency, issue.account); +} + +// Overload with depth parameter for uniformity with MPTIssue version. +// The depth parameter is ignored for IOUs since they don't have vault recursion. +[[nodiscard]] inline bool +isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int /*depth*/) +{ + return isFrozen(view, account, issue); +} + +[[nodiscard]] bool +isDeepFrozen( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer); + +[[nodiscard]] inline bool +isDeepFrozen( + ReadView const& view, + AccountID const& account, + Issue const& issue, + int = 0 /*ignored*/) +{ + return isDeepFrozen(view, account, issue.currency, issue.account); +} + +[[nodiscard]] inline TER +checkDeepFrozen(ReadView const& view, AccountID const& account, Issue const& issue) +{ + return isDeepFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS; +} + +//------------------------------------------------------------------------------ +// +// Trust line operations +// +//------------------------------------------------------------------------------ + +/** Create a trust line + + This can set an initial balance. +*/ +[[nodiscard]] TER +trustCreate( + ApplyView& view, + bool const bSrcHigh, + AccountID const& uSrcAccountID, + AccountID const& uDstAccountID, + uint256 const& uIndex, // --> ripple state entry + SLE::ref sleAccount, // --> the account being set. + bool const bAuth, // --> authorize account. + bool const bNoRipple, // --> others cannot ripple through + bool const bFreeze, // --> funds cannot leave + bool bDeepFreeze, // --> can neither receive nor send funds + STAmount const& saBalance, // --> balance of account being set. + // Issuer should be noAccount() + STAmount const& saLimit, // --> limit for account being set. + // Issuer should be the account being set. + std::uint32_t uQualityIn, + std::uint32_t uQualityOut, + beast::Journal j); + +[[nodiscard]] TER +trustDelete( + ApplyView& view, + std::shared_ptr const& sleRippleState, + AccountID const& uLowAccountID, + AccountID const& uHighAccountID, + beast::Journal j); + +//------------------------------------------------------------------------------ +// +// IOU issuance/redemption +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +issueIOU( + ApplyView& view, + AccountID const& account, + STAmount const& amount, + Issue const& issue, + beast::Journal j); + +[[nodiscard]] TER +redeemIOU( + ApplyView& view, + AccountID const& account, + STAmount const& amount, + Issue const& issue, + beast::Journal j); + +//------------------------------------------------------------------------------ +// +// Authorization and transfer checks (IOU-specific) +// +//------------------------------------------------------------------------------ + +/** Check if the account lacks required authorization. + * + * Return tecNO_AUTH or tecNO_LINE if it does + * and tesSUCCESS otherwise. + * + * If StrongAuth then return tecNO_LINE if the RippleState doesn't exist. Return + * tecNO_AUTH if lsfRequireAuth is set on the issuer's AccountRoot, and the + * RippleState does exist, and the RippleState is not authorized. + * + * If WeakAuth then return tecNO_AUTH if lsfRequireAuth is set, and the + * RippleState exists, and is not authorized. Return tecNO_LINE if + * lsfRequireAuth is set and the RippleState doesn't exist. Consequently, if + * WeakAuth and lsfRequireAuth is *not* set, this function will return + * tesSUCCESS even if RippleState does *not* exist. + * + * The default "Legacy" auth type is equivalent to WeakAuth. + */ +[[nodiscard]] TER +requireAuth( + ReadView const& view, + Issue const& issue, + AccountID const& account, + AuthType authType = AuthType::Legacy); + +/** Check if the destination account is allowed + * to receive IOU. Return terNO_RIPPLE if rippling is + * disabled on both sides and tesSUCCESS otherwise. + */ +[[nodiscard]] TER +canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to); + +//------------------------------------------------------------------------------ +// +// Empty holding operations (IOU-specific) +// +//------------------------------------------------------------------------------ + +/// Any transactors that call addEmptyHolding() in doApply must call +/// canAddHolding() in preflight with the same View and Asset +[[nodiscard]] TER +addEmptyHolding( + ApplyView& view, + AccountID const& accountID, + XRPAmount priorBalance, + Issue const& issue, + beast::Journal journal); + +[[nodiscard]] TER +removeEmptyHolding( + ApplyView& view, + AccountID const& accountID, + Issue const& issue, + beast::Journal journal); + +/** Delete trustline to AMM. The passed `sle` must be obtained from a prior + * call to view.peek(). Fail if neither side of the trustline is AMM or + * if ammAccountID is seated and is not one of the trustline's side. + */ +[[nodiscard]] TER +deleteAMMTrustLine( + ApplyView& view, + std::shared_ptr sleState, + std::optional const& ammAccountID, + beast::Journal j); + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/TokenHelpers.h b/include/xrpl/ledger/helpers/TokenHelpers.h new file mode 100644 index 0000000000..74d1e4848e --- /dev/null +++ b/include/xrpl/ledger/helpers/TokenHelpers.h @@ -0,0 +1,286 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl { + +//------------------------------------------------------------------------------ +// +// Enums for token handling +// +//------------------------------------------------------------------------------ + +/** Controls the treatment of frozen account balances */ +enum FreezeHandling { fhIGNORE_FREEZE, fhZERO_IF_FROZEN }; + +/** Controls the treatment of unauthorized MPT balances */ +enum AuthHandling { ahIGNORE_AUTH, ahZERO_IF_UNAUTHORIZED }; + +/** Controls whether to include the account's full spendable balance */ +enum SpendableHandling { shSIMPLE_BALANCE, shFULL_BALANCE }; + +enum class WaiveTransferFee : bool { No = false, Yes }; + +/* Check if MPToken (for MPT) or trust line (for IOU) exists: + * - StrongAuth - before checking if authorization is required + * - WeakAuth + * for MPT - after checking lsfMPTRequireAuth flag + * for IOU - do not check if trust line exists + * - Legacy + * for MPT - before checking lsfMPTRequireAuth flag i.e. same as StrongAuth + * for IOU - do not check if trust line exists i.e. same as WeakAuth + */ +enum class AuthType { StrongAuth, WeakAuth, Legacy }; + +//------------------------------------------------------------------------------ +// +// Freeze checking (Asset-based dispatchers) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] bool +isGlobalFrozen(ReadView const& view, Asset const& asset); + +[[nodiscard]] bool +isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset); + +/** + * isFrozen check is recursive for MPT shares in a vault, descending to + * assets in the vault, up to maxAssetCheckDepth recursion depth. This is + * purely defensive, as we currently do not allow such vaults to be created. + */ +[[nodiscard]] bool +isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0); + +[[nodiscard]] TER +checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue); + +[[nodiscard]] TER +checkFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue); + +[[nodiscard]] TER +checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset); + +[[nodiscard]] bool +isAnyFrozen( + ReadView const& view, + std::initializer_list const& accounts, + Issue const& issue); + +[[nodiscard]] bool +isAnyFrozen( + ReadView const& view, + std::initializer_list const& accounts, + Asset const& asset, + int depth = 0); + +[[nodiscard]] bool +isDeepFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue, + int depth = 0); + +/** + * isFrozen check is recursive for MPT shares in a vault, descending to + * assets in the vault, up to maxAssetCheckDepth recursion depth. This is + * purely defensive, as we currently do not allow such vaults to be created. + */ +[[nodiscard]] bool +isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0); + +[[nodiscard]] TER +checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue); + +[[nodiscard]] TER +checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset); + +//------------------------------------------------------------------------------ +// +// Account balance functions (Asset-based dispatchers) +// +//------------------------------------------------------------------------------ + +// Returns the amount an account can spend. +// +// If shSIMPLE_BALANCE is specified, this is the amount the account can spend +// without going into debt. +// +// If shFULL_BALANCE is specified, this is the amount the account can spend +// total. Specifically: +// * The account can go into debt if using a trust line, and the other side has +// a non-zero limit. +// * If the account is the asset issuer the limit is defined by the asset / +// issuance. +// +// <-- saAmount: amount of currency held by account. May be negative. +[[nodiscard]] STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + FreezeHandling zeroIfFrozen, + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); + +[[nodiscard]] STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Issue const& issue, + FreezeHandling zeroIfFrozen, + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); + +[[nodiscard]] STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue, + FreezeHandling zeroIfFrozen, + AuthHandling zeroIfUnauthorized, + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); + +[[nodiscard]] STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Asset const& asset, + FreezeHandling zeroIfFrozen, + AuthHandling zeroIfUnauthorized, + beast::Journal j, + SpendableHandling includeFullBalance = shSIMPLE_BALANCE); + +// Returns the amount an account can spend of the currency type saDefault, or +// returns saDefault if this account is the issuer of the currency in +// question. Should be used in favor of accountHolds when questioning how much +// an account can spend while also allowing currency issuers to spend +// unlimited amounts of their own currency (since they can always issue more). +[[nodiscard]] STAmount +accountFunds( + ReadView const& view, + AccountID const& id, + STAmount const& saDefault, + FreezeHandling freezeHandling, + beast::Journal j); + +/** Returns the transfer fee as Rate based on the type of token + * @param view The ledger view + * @param amount The amount to transfer + */ +[[nodiscard]] Rate +transferRate(ReadView const& view, STAmount const& amount); + +//------------------------------------------------------------------------------ +// +// Holding operations (Asset-based dispatchers) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +canAddHolding(ReadView const& view, Asset const& asset); + +[[nodiscard]] TER +addEmptyHolding( + ApplyView& view, + AccountID const& accountID, + XRPAmount priorBalance, + Asset const& asset, + beast::Journal journal); + +[[nodiscard]] TER +removeEmptyHolding( + ApplyView& view, + AccountID const& accountID, + Asset const& asset, + beast::Journal journal); + +//------------------------------------------------------------------------------ +// +// Authorization and transfer checks (Asset-based dispatchers) +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +requireAuth( + ReadView const& view, + Asset const& asset, + AccountID const& account, + AuthType authType = AuthType::Legacy); + +[[nodiscard]] TER +canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, AccountID const& to); + +//------------------------------------------------------------------------------ +// +// Money Transfers (Asset-based dispatchers) +// +//------------------------------------------------------------------------------ + +// Direct send w/o fees: +// - Redeeming IOUs and/or sending sender's own IOUs. +// - Create trust line of needed. +// --> bCheckIssuer : normally require issuer to be involved. +// [[nodiscard]] // nodiscard commented out so DirectStep.cpp compiles. + +/** Calls static rippleCreditIOU if saAmount represents Issue. + * Calls static rippleCreditMPT if saAmount represents MPTIssue. + */ +TER +rippleCredit( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + bool bCheckIssuer, + beast::Journal j); + +/** Calls static accountSendIOU if saAmount represents Issue. + * Calls static accountSendMPT if saAmount represents MPTIssue. + */ +[[nodiscard]] TER +accountSend( + ApplyView& view, + AccountID const& from, + AccountID const& to, + STAmount const& saAmount, + beast::Journal j, + WaiveTransferFee waiveFee = WaiveTransferFee::No); + +using MultiplePaymentDestinations = std::vector>; +/** Like accountSend, except one account is sending multiple payments (with the + * same asset!) simultaneously + * + * Calls static accountSendMultiIOU if saAmount represents Issue. + * Calls static accountSendMultiMPT if saAmount represents MPTIssue. + */ +[[nodiscard]] TER +accountSendMulti( + ApplyView& view, + AccountID const& senderID, + Asset const& asset, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee = WaiveTransferFee::No); + +[[nodiscard]] TER +transferXRP( + ApplyView& view, + AccountID const& from, + AccountID const& to, + STAmount const& amount, + beast::Journal j); + +} // namespace xrpl diff --git a/include/xrpl/ledger/helpers/VaultHelpers.h b/include/xrpl/ledger/helpers/VaultHelpers.h new file mode 100644 index 0000000000..8aef30aa27 --- /dev/null +++ b/include/xrpl/ledger/helpers/VaultHelpers.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include + +#include +#include + +namespace xrpl { + +/** From the perspective of a vault, return the number of shares to give + depositor when they offer a fixed amount of assets. Note, since shares are + MPT, this number is integral and always truncated in this calculation. + + @param vault The vault SLE. + @param issuance The MPTokenIssuance SLE for the vault's shares. + @param assets The amount of assets to convert. + + @return The number of shares, or nullopt on error. +*/ +[[nodiscard]] std::optional +assetsToSharesDeposit( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& assets); + +/** From the perspective of a vault, return the number of assets to take from + depositor when they receive a fixed amount of shares. Note, since shares are + MPT, they are always an integral number. + + @param vault The vault SLE. + @param issuance The MPTokenIssuance SLE for the vault's shares. + @param shares The amount of shares to convert. + + @return The number of assets, or nullopt on error. +*/ +[[nodiscard]] std::optional +sharesToAssetsDeposit( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& shares); + +/** Controls whether to truncate shares instead of rounding. */ +enum class TruncateShares : bool { no = false, yes = true }; + +/** From the perspective of a vault, return the number of shares to demand from + the depositor when they ask to withdraw a fixed amount of assets. Since + shares are MPT this number is integral, and it will be rounded to nearest + unless explicitly requested to be truncated instead. + + @param vault The vault SLE. + @param issuance The MPTokenIssuance SLE for the vault's shares. + @param assets The amount of assets to convert. + @param truncate Whether to truncate instead of rounding. + + @return The number of shares, or nullopt on error. +*/ +[[nodiscard]] std::optional +assetsToSharesWithdraw( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& assets, + TruncateShares truncate = TruncateShares::no); + +/** From the perspective of a vault, return the number of assets to give the + depositor when they redeem a fixed amount of shares. Note, since shares are + MPT, they are always an integral number. + + @param vault The vault SLE. + @param issuance The MPTokenIssuance SLE for the vault's shares. + @param shares The amount of shares to convert. + + @return The number of assets, or nullopt on error. +*/ +[[nodiscard]] std::optional +sharesToAssetsWithdraw( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& shares); + +} // namespace xrpl diff --git a/include/xrpl/tx/paths/detail/StrandFlow.h b/include/xrpl/tx/paths/detail/StrandFlow.h index 67e333f2e6..f99f54d0e8 100644 --- a/include/xrpl/tx/paths/detail/StrandFlow.h +++ b/include/xrpl/tx/paths/detail/StrandFlow.h @@ -1,7 +1,8 @@ #pragma once #include -#include +#include +#include #include #include #include diff --git a/src/libxrpl/ledger/Credit.cpp b/src/libxrpl/ledger/Credit.cpp deleted file mode 100644 index 0a0283c3b8..0000000000 --- a/src/libxrpl/ledger/Credit.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -namespace xrpl { - -STAmount -creditLimit( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency) -{ - STAmount result(Issue{currency, account}); - - auto sleRippleState = view.read(keylet::line(account, issuer, currency)); - - if (sleRippleState) - { - result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit); - result.setIssuer(account); - } - - XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditLimit : result issuer match"); - XRPL_ASSERT(result.getCurrency() == currency, "xrpl::creditLimit : result currency match"); - return result; -} - -IOUAmount -creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur) -{ - return toAmount(creditLimit(v, acc, iss, cur)); -} - -STAmount -creditBalance( - ReadView const& view, - AccountID const& account, - AccountID const& issuer, - Currency const& currency) -{ - STAmount result(Issue{currency, account}); - - auto sleRippleState = view.read(keylet::line(account, issuer, currency)); - - if (sleRippleState) - { - result = sleRippleState->getFieldAmount(sfBalance); - if (account < issuer) - result.negate(); - result.setIssuer(account); - } - - XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditBalance : result issuer match"); - XRPL_ASSERT(result.getCurrency() == currency, "xrpl::creditBalance : result currency match"); - return result; -} - -} // namespace xrpl diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index d5c94a9981..f51fb97993 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -2,10 +2,9 @@ #include #include #include -#include -#include #include #include +#include #include #include #include @@ -22,133 +21,6 @@ namespace xrpl { -namespace detail { - -template < - class V, - class N, - class = std::enable_if_t< - std::is_same_v, SLE> && std::is_base_of_v>> -bool -internalDirNext( - V& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) -{ - auto const& svIndexes = page->getFieldV256(sfIndexes); - XRPL_ASSERT(index <= svIndexes.size(), "xrpl::detail::internalDirNext : index inside range"); - - if (index >= svIndexes.size()) - { - auto const next = page->getFieldU64(sfIndexNext); - - if (!next) - { - entry.zero(); - return false; - } - - if constexpr (std::is_const_v) - { - page = view.read(keylet::page(root, next)); - } - else - { - page = view.peek(keylet::page(root, next)); - } - - XRPL_ASSERT(page, "xrpl::detail::internalDirNext : non-null root"); - - if (!page) - return false; - - index = 0; - - return internalDirNext(view, root, page, index, entry); - } - - entry = svIndexes[index++]; - return true; -} - -template < - class V, - class N, - class = std::enable_if_t< - std::is_same_v, SLE> && std::is_base_of_v>> -bool -internalDirFirst( - V& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) -{ - if constexpr (std::is_const_v) - { - page = view.read(keylet::page(root)); - } - else - { - page = view.peek(keylet::page(root)); - } - - if (!page) - return false; - - index = 0; - - return internalDirNext(view, root, page, index, entry); -} - -} // namespace detail - -bool -dirFirst( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) -{ - return detail::internalDirFirst(view, root, page, index, entry); -} - -bool -dirNext( - ApplyView& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) -{ - return detail::internalDirNext(view, root, page, index, entry); -} - -bool -cdirFirst( - ReadView const& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) -{ - return detail::internalDirFirst(view, root, page, index, entry); -} - -bool -cdirNext( - ReadView const& view, - uint256 const& root, - std::shared_ptr& page, - unsigned int& index, - uint256& entry) -{ - return detail::internalDirNext(view, root, page, index, entry); -} - //------------------------------------------------------------------------------ // // Observers @@ -164,124 +36,6 @@ hasExpired(ReadView const& view, std::optional const& exp) return exp && (view.parentCloseTime() >= tp{d{*exp}}); } -bool -isGlobalFrozen(ReadView const& view, AccountID const& issuer) -{ - if (isXRP(issuer)) - return false; - if (auto const sle = view.read(keylet::account(issuer))) - return sle->isFlag(lsfGlobalFreeze); - return false; -} - -bool -isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue) -{ - if (auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID()))) - return sle->isFlag(lsfMPTLocked); - return false; -} - -bool -isGlobalFrozen(ReadView const& view, Asset const& asset) -{ - return std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - { - return isGlobalFrozen(view, issue.getIssuer()); - } - else - { - return isGlobalFrozen(view, issue); - } - }, - asset.value()); -} - -bool -isIndividualFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer) -{ - if (isXRP(currency)) - return false; - if (issuer != account) - { - // Check if the issuer froze the line - auto const sle = view.read(keylet::line(account, issuer, currency)); - if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) - return true; - } - return false; -} - -bool -isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) -{ - if (auto const sle = view.read(keylet::mptoken(mptIssue.getMptID(), account))) - return sle->isFlag(lsfMPTLocked); - return false; -} - -// Can the specified account spend the specified currency issued by -// the specified issuer or does the freeze flag prohibit it? -bool -isFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer) -{ - if (isXRP(currency)) - return false; - auto sle = view.read(keylet::account(issuer)); - if (sle && sle->isFlag(lsfGlobalFreeze)) - return true; - if (issuer != account) - { - // Check if the issuer froze the line - sle = view.read(keylet::line(account, issuer, currency)); - if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) - return true; - } - return false; -} - -bool -isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth) -{ - return isGlobalFrozen(view, mptIssue) || isIndividualFrozen(view, account, mptIssue) || - isVaultPseudoAccountFrozen(view, account, mptIssue, depth); -} - -[[nodiscard]] bool -isAnyFrozen( - ReadView const& view, - std::initializer_list const& accounts, - MPTIssue const& mptIssue, - int depth) -{ - if (isGlobalFrozen(view, mptIssue)) - return true; - - for (auto const& account : accounts) - { - if (isIndividualFrozen(view, account, mptIssue)) - return true; - } - - for (auto const& account : accounts) - { - if (isVaultPseudoAccountFrozen(view, account, mptIssue, depth)) - return true; - } - - return false; -} - bool isVaultPseudoAccountFrozen( ReadView const& view, @@ -323,32 +77,6 @@ isVaultPseudoAccountFrozen( return isAnyFrozen(view, {issuer, account}, vault->at(sfAsset), depth + 1); } -bool -isDeepFrozen( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer) -{ - if (isXRP(currency)) - { - return false; - } - - if (issuer == account) - { - return false; - } - - auto const sle = view.read(keylet::line(account, issuer, currency)); - if (!sle) - { - return false; - } - - return sle->isFlag(lsfHighDeepFreeze) || sle->isFlag(lsfLowDeepFreeze); -} - bool isLPTokenFrozen( ReadView const& view, @@ -360,468 +88,6 @@ isLPTokenFrozen( isFrozen(view, account, asset2.currency, asset2.account); } -static SLE::const_pointer -getLineIfUsable( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer, - FreezeHandling zeroIfFrozen, - beast::Journal j) -{ - auto const sle = view.read(keylet::line(account, issuer, currency)); - - if (!sle) - { - return nullptr; - } - - if (zeroIfFrozen == fhZERO_IF_FROZEN) - { - if (isFrozen(view, account, currency, issuer) || - isDeepFrozen(view, account, currency, issuer)) - { - return nullptr; - } - - // when fixFrozenLPTokenTransfer is enabled, if currency is lptoken, - // we need to check if the associated assets have been frozen - if (view.rules().enabled(fixFrozenLPTokenTransfer)) - { - auto const sleIssuer = view.read(keylet::account(issuer)); - if (!sleIssuer) - { - return nullptr; // LCOV_EXCL_LINE - } - if (sleIssuer->isFieldPresent(sfAMMID)) - { - auto const sleAmm = view.read(keylet::amm((*sleIssuer)[sfAMMID])); - - if (!sleAmm || - isLPTokenFrozen( - view, - account, - (*sleAmm)[sfAsset].get(), - (*sleAmm)[sfAsset2].get())) - { - return nullptr; - } - } - } - } - - return sle; -} - -static STAmount -getTrustLineBalance( - ReadView const& view, - SLE::const_ref sle, - AccountID const& account, - Currency const& currency, - AccountID const& issuer, - bool includeOppositeLimit, - beast::Journal j) -{ - STAmount amount; - if (sle) - { - amount = sle->getFieldAmount(sfBalance); - bool const accountHigh = account > issuer; - auto const& oppositeField = accountHigh ? sfLowLimit : sfHighLimit; - if (accountHigh) - { - // Put balance in account terms. - amount.negate(); - } - if (includeOppositeLimit) - { - amount += sle->getFieldAmount(oppositeField); - } - amount.setIssuer(issuer); - } - else - { - amount.clear(Issue{currency, issuer}); - } - - JLOG(j.trace()) << "getTrustLineBalance:" << " account=" << to_string(account) - << " amount=" << amount.getFullText(); - - return view.balanceHook(account, issuer, amount); -} - -STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - Currency const& currency, - AccountID const& issuer, - FreezeHandling zeroIfFrozen, - beast::Journal j, - SpendableHandling includeFullBalance) -{ - STAmount amount; - if (isXRP(currency)) - { - return {xrpLiquid(view, account, 0, j)}; - } - - bool const returnSpendable = (includeFullBalance == shFULL_BALANCE); - if (returnSpendable && account == issuer) - { - // If the account is the issuer, then their limit is effectively - // infinite - return STAmount{Issue{currency, issuer}, STAmount::cMaxValue, STAmount::cMaxOffset}; - } - - // IOU: Return balance on trust line modulo freeze - SLE::const_pointer const sle = - getLineIfUsable(view, account, currency, issuer, zeroIfFrozen, j); - - return getTrustLineBalance(view, sle, account, currency, issuer, returnSpendable, j); -} - -STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - Issue const& issue, - FreezeHandling zeroIfFrozen, - beast::Journal j, - SpendableHandling includeFullBalance) -{ - return accountHolds( - view, account, issue.currency, issue.account, zeroIfFrozen, j, includeFullBalance); -} - -STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - MPTIssue const& mptIssue, - FreezeHandling zeroIfFrozen, - AuthHandling zeroIfUnauthorized, - beast::Journal j, - SpendableHandling includeFullBalance) -{ - bool const returnSpendable = (includeFullBalance == shFULL_BALANCE); - - if (returnSpendable && account == mptIssue.getIssuer()) - { - // if the account is the issuer, and the issuance exists, their limit is - // the issuance limit minus the outstanding value - auto const issuance = view.read(keylet::mptIssuance(mptIssue.getMptID())); - - if (!issuance) - { - return STAmount{mptIssue}; - } - return STAmount{ - mptIssue, - issuance->at(~sfMaximumAmount).value_or(maxMPTokenAmount) - - issuance->at(sfOutstandingAmount)}; - } - - STAmount amount; - - auto const sleMpt = view.read(keylet::mptoken(mptIssue.getMptID(), account)); - - if (!sleMpt) - { - amount.clear(mptIssue); - } - else if (zeroIfFrozen == fhZERO_IF_FROZEN && isFrozen(view, account, mptIssue)) - { - amount.clear(mptIssue); - } - else - { - amount = STAmount{mptIssue, sleMpt->getFieldU64(sfMPTAmount)}; - - // Only if auth check is needed, as it needs to do an additional read - // operation. Note featureSingleAssetVault will affect error codes. - if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED && - view.rules().enabled(featureSingleAssetVault)) - { - if (auto const err = requireAuth(view, mptIssue, account, AuthType::StrongAuth); - !isTesSuccess(err)) - amount.clear(mptIssue); - } - else if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED) - { - auto const sleIssuance = view.read(keylet::mptIssuance(mptIssue.getMptID())); - - // if auth is enabled on the issuance and mpt is not authorized, - // clear amount - if (sleIssuance && sleIssuance->isFlag(lsfMPTRequireAuth) && - !sleMpt->isFlag(lsfMPTAuthorized)) - amount.clear(mptIssue); - } - } - - return amount; -} - -[[nodiscard]] STAmount -accountHolds( - ReadView const& view, - AccountID const& account, - Asset const& asset, - FreezeHandling zeroIfFrozen, - AuthHandling zeroIfUnauthorized, - beast::Journal j, - SpendableHandling includeFullBalance) -{ - return std::visit( - [&](TIss const& value) { - if constexpr (std::is_same_v) - { - return accountHolds(view, account, value, zeroIfFrozen, j, includeFullBalance); - } - else if constexpr (std::is_same_v) - { - return accountHolds( - view, account, value, zeroIfFrozen, zeroIfUnauthorized, j, includeFullBalance); - } - }, - asset.value()); -} - -STAmount -accountFunds( - ReadView const& view, - AccountID const& id, - STAmount const& saDefault, - FreezeHandling freezeHandling, - beast::Journal j) -{ - if (!saDefault.native() && saDefault.getIssuer() == id) - return saDefault; - - return accountHolds( - view, id, saDefault.getCurrency(), saDefault.getIssuer(), freezeHandling, j); -} - -// Prevent ownerCount from wrapping under error conditions. -// -// 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 -confineOwnerCount( - std::uint32_t current, - std::int32_t adjustment, - std::optional const& id = std::nullopt, - beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) -{ - std::uint32_t adjusted{current + adjustment}; - if (adjustment > 0) - { - // Overflow is well defined on unsigned - if (adjusted < current) - { - if (id) - { - JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!"; - } - adjusted = std::numeric_limits::max(); - } - } - else - { - // Underflow is well defined on unsigned - if (adjusted > current) - { - if (id) - { - JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!"; - } - adjusted = 0; - XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set"); - } - } - return adjusted; -} - -XRPAmount -xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j) -{ - auto const sle = view.read(keylet::account(id)); - if (sle == nullptr) - return beast::zero; - - // Return balance minus reserve - std::uint32_t const ownerCount = - confineOwnerCount(view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj); - - // Pseudo-accounts have no reserve requirement - auto const reserve = - isPseudoAccount(sle) ? XRPAmount{0} : view.fees().accountReserve(ownerCount); - - auto const fullBalance = sle->getFieldAmount(sfBalance); - - auto const balance = view.balanceHook(id, xrpAccount(), fullBalance); - - STAmount const amount = (balance < reserve) ? STAmount{0} : balance - reserve; - - JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id) - << " amount=" << amount.getFullText() - << " fullBalance=" << fullBalance.getFullText() - << " balance=" << balance.getFullText() << " reserve=" << reserve - << " ownerCount=" << ownerCount << " ownerCountAdj=" << ownerCountAdj; - - return amount.xrp(); -} - -void -forEachItem( - ReadView const& view, - Keylet const& root, - std::function const&)> const& f) -{ - XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::forEachItem : valid root type"); - - if (root.type != ltDIR_NODE) - return; - - auto pos = root; - - while (true) - { - auto sle = view.read(pos); - if (!sle) - return; - for (auto const& key : sle->getFieldV256(sfIndexes)) - f(view.read(keylet::child(key))); - auto const next = sle->getFieldU64(sfIndexNext); - if (!next) - return; - pos = keylet::page(root, next); - } -} - -bool -forEachItemAfter( - ReadView const& view, - Keylet const& root, - uint256 const& after, - std::uint64_t const hint, - unsigned int limit, - std::function const&)> const& f) -{ - XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::forEachItemAfter : valid root type"); - - if (root.type != ltDIR_NODE) - return false; - - auto currentIndex = root; - - // If startAfter is not zero try jumping to that page using the hint - if (after.isNonZero()) - { - auto const hintIndex = keylet::page(root, hint); - - if (auto hintDir = view.read(hintIndex)) - { - for (auto const& key : hintDir->getFieldV256(sfIndexes)) - { - if (key == after) - { - // We found the hint, we can start here - currentIndex = hintIndex; - break; - } - } - } - - bool found = false; - for (;;) - { - auto const ownerDir = view.read(currentIndex); - if (!ownerDir) - return found; - for (auto const& key : ownerDir->getFieldV256(sfIndexes)) - { - if (!found) - { - if (key == after) - found = true; - } - else if (f(view.read(keylet::child(key))) && limit-- <= 1) - { - return found; - } - } - - auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext); - if (uNodeNext == 0) - return found; - currentIndex = keylet::page(root, uNodeNext); - } - } - else - { - for (;;) - { - auto const ownerDir = view.read(currentIndex); - if (!ownerDir) - return true; - for (auto const& key : ownerDir->getFieldV256(sfIndexes)) - { - if (f(view.read(keylet::child(key))) && limit-- <= 1) - return true; - } - auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext); - if (uNodeNext == 0) - return true; - currentIndex = keylet::page(root, uNodeNext); - } - } -} - -Rate -transferRate(ReadView const& view, AccountID const& issuer) -{ - auto const sle = view.read(keylet::account(issuer)); - - if (sle && sle->isFieldPresent(sfTransferRate)) - return Rate{sle->getFieldU32(sfTransferRate)}; - - return parityRate; -} - -Rate -transferRate(ReadView const& view, MPTID const& issuanceID) -{ - // fee is 0-50,000 (0-50%), rate is 1,000,000,000-2,000,000,000 - // For example, if transfer fee is 50% then 10,000 * 50,000 = 500,000 - // which represents 50% of 1,000,000,000 - if (auto const sle = view.read(keylet::mptIssuance(issuanceID)); - sle && sle->isFieldPresent(sfTransferFee)) - return Rate{1'000'000'000u + 10'000 * sle->getFieldU16(sfTransferFee)}; - - return parityRate; -} - -Rate -transferRate(ReadView const& view, STAmount const& amount) -{ - return std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - { - return transferRate(view, issue.getIssuer()); - } - else - { - return transferRate(view, issue.getMptID()); - } - }, - amount.asset().value()); -} - bool areCompatible( ReadView const& validLedger, @@ -920,20 +186,6 @@ areCompatible( return ret; } -bool -dirIsEmpty(ReadView const& view, Keylet const& k) -{ - auto const sleNode = view.read(k); - if (!sleNode) - return true; - if (!sleNode->getFieldV256(sfIndexes).empty()) - return false; - // The first page of a directory may legitimately be empty even if there - // are other pages (the first page is the anchor page) so check to see if - // there is another page. If there is, the directory isn't empty. - return sleNode->getFieldU64(sfIndexNext) == 0; -} - std::set getEnabledAmendments(ReadView const& view) { @@ -1037,30 +289,6 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) // //------------------------------------------------------------------------------ -void -adjustOwnerCount( - ApplyView& view, - std::shared_ptr const& sle, - std::int32_t amount, - 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); -} - -std::function -describeOwnerDir(AccountID const& account) -{ - return [account](std::shared_ptr const& sle) { (*sle)[sfOwner] = account; }; -} - TER dirLink( ApplyView& view, @@ -1076,168 +304,6 @@ dirLink( return tesSUCCESS; } -AccountID -pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey) -{ - // This number must not be changed without an amendment - constexpr std::uint16_t maxAccountAttempts = 256; - for (std::uint16_t i = 0; i < maxAccountAttempts; ++i) - { - ripesha_hasher rsh; - auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey); - rsh(hash.data(), hash.size()); - AccountID const ret{static_cast(rsh)}; - if (!view.read(keylet::account(ret))) - return ret; - } - return beast::zero; -} - -// Pseudo-account designator fields MUST be maintained by including the -// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to -// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated, -// since a non-active amendment will not set any field, by definition. -// Specific properties of a pseudo-account are NOT checked here, that's what -// InvariantCheck is for. -[[nodiscard]] std::vector const& -getPseudoAccountFields() -{ - static std::vector const pseudoFields = []() { - auto const ar = LedgerFormats::getInstance().findByType(ltACCOUNT_ROOT); - if (!ar) - { - // LCOV_EXCL_START - LogicError( - "xrpl::getPseudoAccountFields : unable to find account root " - "ledger format"); - // LCOV_EXCL_STOP - } - auto const& soTemplate = ar->getSOTemplate(); - - std::vector pseudoFields; - for (auto const& field : soTemplate) - { - if (field.sField().shouldMeta(SField::sMD_PseudoAccount)) - pseudoFields.emplace_back(&field.sField()); - } - return pseudoFields; - }(); - return pseudoFields; -} - -[[nodiscard]] bool -isPseudoAccount( - std::shared_ptr sleAcct, - std::set const& pseudoFieldFilter) -{ - auto const& fields = getPseudoAccountFields(); - - // Intentionally use defensive coding here because it's cheap and makes the - // semantics of true return value clean. - return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT && - std::count_if( - fields.begin(), fields.end(), [&sleAcct, &pseudoFieldFilter](SField const* sf) -> bool { - return sleAcct->isFieldPresent(*sf) && - (pseudoFieldFilter.empty() || pseudoFieldFilter.contains(sf)); - }) > 0; -} - -Expected, TER> -createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField) -{ - [[maybe_unused]] - auto const& fields = getPseudoAccountFields(); - XRPL_ASSERT( - std::count_if( - fields.begin(), - fields.end(), - [&ownerField](SField const* sf) -> bool { return *sf == ownerField; }) == 1, - "xrpl::createPseudoAccount : valid owner field"); - - auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey); - if (accountId == beast::zero) - return Unexpected(tecDUPLICATE); - - // Create pseudo-account. - auto account = std::make_shared(keylet::account(accountId)); - account->setAccountID(sfAccount, accountId); - account->setFieldAmount(sfBalance, STAmount{}); - - // Pseudo-accounts can't submit transactions, so set the sequence number - // to 0 to make them easier to spot and verify, and add an extra level - // of protection. - std::uint32_t const seqno = // - view.rules().enabled(featureSingleAssetVault) || // - view.rules().enabled(featureLendingProtocol) // - ? 0 // - : view.seq(); - account->setFieldU32(sfSequence, seqno); - // Ignore reserves requirement, disable the master key, allow default - // rippling, and enable deposit authorization to prevent payments into - // pseudo-account. - account->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); - // Link the pseudo-account with its owner object. - account->setFieldH256(ownerField, pseudoOwnerKey); - - view.insert(account); - - return account; -} - -[[nodiscard]] TER -canAddHolding(ReadView const& view, Issue const& issue) -{ - if (issue.native()) - return tesSUCCESS; // No special checks for XRP - - auto const issuer = view.read(keylet::account(issue.getIssuer())); - if (!issuer) - { - return terNO_ACCOUNT; - } - if (!issuer->isFlag(lsfDefaultRipple)) - { - return terNO_RIPPLE; - } - - return tesSUCCESS; -} - -[[nodiscard]] TER -canAddHolding(ReadView const& view, MPTIssue const& mptIssue) -{ - auto mptID = mptIssue.getMptID(); - auto issuance = view.read(keylet::mptIssuance(mptID)); - if (!issuance) - return tecOBJECT_NOT_FOUND; - if (!issuance->isFlag(lsfMPTCanTransfer)) - return tecNO_AUTH; - - return tesSUCCESS; -} - -[[nodiscard]] TER -canAddHolding(ReadView const& view, Asset const& asset) -{ - return std::visit( - [&](TIss const& issue) -> TER { return canAddHolding(view, issue); }, - asset.value()); -} - -[[nodiscard]] TER -checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag) -{ - if (toSle == nullptr) - return tecNO_DST; - - // The tag is basically account-specific information we don't - // understand, but we can require someone to fill it in. - if (toSle->isFlag(lsfRequireDestTag) && !hasDestinationTag) - return tecDST_TAG_NEEDED; // Cannot send without a tag - - return tesSUCCESS; -} - /* * Checks if a withdrawal amount into the destination account exceeds * any applicable receiving limit. @@ -1375,1837 +441,6 @@ doWithdraw( return accountSend(view, sourceAcct, dstAcct, amount, j, WaiveTransferFee::Yes); } -[[nodiscard]] TER -addEmptyHolding( - ApplyView& view, - AccountID const& accountID, - XRPAmount priorBalance, - Issue const& issue, - beast::Journal journal) -{ - // Every account can hold XRP. An issuer can issue directly. - if (issue.native() || accountID == issue.getIssuer()) - return tesSUCCESS; - - auto const& issuerId = issue.getIssuer(); - auto const& currency = issue.currency; - if (isGlobalFrozen(view, issuerId)) - return tecFROZEN; // LCOV_EXCL_LINE - - auto const& srcId = issuerId; - auto const& dstId = accountID; - auto const high = srcId > dstId; - auto const index = keylet::line(srcId, dstId, currency); - auto const sleSrc = view.peek(keylet::account(srcId)); - auto const sleDst = 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)) - return tecDUPLICATE; - - // 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; - - return trustCreate( - view, - high, - srcId, - dstId, - index.key, - sleDst, - /*bAuth=*/false, - /*bNoRipple=*/true, - /*bFreeze=*/false, - /*deepFreeze*/ false, - /*saBalance=*/STAmount{Issue{currency, noAccount()}}, - /*saLimit=*/STAmount{Issue{currency, dstId}}, - /*uSrcQualityIn=*/0, - /*uSrcQualityOut=*/0, - journal); -} - -[[nodiscard]] TER -addEmptyHolding( - ApplyView& view, - AccountID const& accountID, - XRPAmount priorBalance, - MPTIssue const& mptIssue, - beast::Journal journal) -{ - auto const& mptID = mptIssue.getMptID(); - auto const mpt = view.peek(keylet::mptIssuance(mptID)); - if (!mpt) - return tefINTERNAL; // LCOV_EXCL_LINE - if (mpt->isFlag(lsfMPTLocked)) - return tefINTERNAL; // LCOV_EXCL_LINE - if (view.peek(keylet::mptoken(mptID, accountID))) - return tecDUPLICATE; - if (accountID == mptIssue.getIssuer()) - return tesSUCCESS; - - return authorizeMPToken(view, priorBalance, mptID, accountID, journal); -} - -[[nodiscard]] TER -authorizeMPToken( - ApplyView& view, - XRPAmount const& priorBalance, - MPTID const& mptIssuanceID, - AccountID const& account, - beast::Journal journal, - std::uint32_t flags, - std::optional holderID) -{ - auto const sleAcct = view.peek(keylet::account(account)); - if (!sleAcct) - return tecINTERNAL; // LCOV_EXCL_LINE - - // If the account that submitted the tx is a holder - // Note: `account_` is holder's account - // `holderID` is NOT used - if (!holderID) - { - // When a holder wants to unauthorize/delete a MPT, the ledger must - // - delete mptokenKey from owner directory - // - delete the MPToken - if (flags & tfMPTUnauthorize) - { - auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); - auto const sleMpt = view.peek(mptokenKey); - if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0) - return tecINTERNAL; // LCOV_EXCL_LINE - - if (!view.dirRemove( - keylet::ownerDir(account), (*sleMpt)[sfOwnerNode], sleMpt->key(), false)) - return tecINTERNAL; // LCOV_EXCL_LINE - - adjustOwnerCount(view, sleAcct, -1, journal); - - view.erase(sleMpt); - return tesSUCCESS; - } - - // A potential holder wants to authorize/hold a mpt, the ledger must: - // - add the new mptokenKey to the owner directory - // - create the MPToken object for the holder - - // 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::zero) - : view.fees().accountReserve(uOwnerCount + 1)); - - if (priorBalance < reserveCreate) - return tecINSUFFICIENT_RESERVE; - - // Defensive check before we attempt to create MPToken for the issuer - auto const mpt = view.read(keylet::mptIssuance(mptIssuanceID)); - if (!mpt || mpt->getAccountID(sfIssuer) == account) - { - // LCOV_EXCL_START - UNREACHABLE("xrpl::authorizeMPToken : invalid issuance or issuers token"); - if (view.rules().enabled(featureLendingProtocol)) - return tecINTERNAL; - // LCOV_EXCL_STOP - } - - auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); - auto mptoken = std::make_shared(mptokenKey); - if (auto ter = dirLink(view, account, mptoken)) - return ter; // LCOV_EXCL_LINE - - (*mptoken)[sfAccount] = account; - (*mptoken)[sfMPTokenIssuanceID] = mptIssuanceID; - (*mptoken)[sfFlags] = 0; - view.insert(mptoken); - - // Update owner count. - adjustOwnerCount(view, sleAcct, 1, journal); - - return tesSUCCESS; - } - - auto const sleMptIssuance = view.read(keylet::mptIssuance(mptIssuanceID)); - if (!sleMptIssuance) - return tecINTERNAL; // LCOV_EXCL_LINE - - // If the account that submitted this tx is the issuer of the MPT - // Note: `account_` is issuer's account - // `holderID` is holder's account - if (account != (*sleMptIssuance)[sfIssuer]) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const sleMpt = view.peek(keylet::mptoken(mptIssuanceID, *holderID)); - if (!sleMpt) - return tecINTERNAL; // LCOV_EXCL_LINE - - std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags); - std::uint32_t flagsOut = flagsIn; - - // Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on - // their MPToken - if (flags & tfMPTUnauthorize) - { - flagsOut &= ~lsfMPTAuthorized; - } - // Issuer wants to authorize a holder, set lsfMPTAuthorized on their - // MPToken - else - { - flagsOut |= lsfMPTAuthorized; - } - - if (flagsIn != flagsOut) - sleMpt->setFieldU32(sfFlags, flagsOut); - - view.update(sleMpt); - return tesSUCCESS; -} - -TER -trustCreate( - ApplyView& view, - bool const bSrcHigh, - AccountID const& uSrcAccountID, - AccountID const& uDstAccountID, - uint256 const& uIndex, // --> ripple state entry - SLE::ref sleAccount, // --> the account being set. - bool const bAuth, // --> authorize account. - bool const bNoRipple, // --> others cannot ripple through - bool const bFreeze, // --> funds cannot leave - bool bDeepFreeze, // --> can neither receive nor send funds - STAmount const& saBalance, // --> balance of account being set. - // Issuer should be noAccount() - STAmount const& saLimit, // --> limit for account being set. - // Issuer should be the account being set. - std::uint32_t uQualityIn, - std::uint32_t uQualityOut, - beast::Journal j) -{ - JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", " - << to_string(uDstAccountID) << ", " << saBalance.getFullText(); - - auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID; - auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID; - if (uLowAccountID == uHighAccountID) - { - // LCOV_EXCL_START - UNREACHABLE("xrpl::trustCreate : trust line to self"); - if (view.rules().enabled(featureLendingProtocol)) - return tecINTERNAL; - // LCOV_EXCL_STOP - } - - auto const sleRippleState = std::make_shared(ltRIPPLE_STATE, uIndex); - view.insert(sleRippleState); - - auto lowNode = view.dirInsert( - keylet::ownerDir(uLowAccountID), sleRippleState->key(), describeOwnerDir(uLowAccountID)); - - if (!lowNode) - return tecDIR_FULL; // LCOV_EXCL_LINE - - auto highNode = view.dirInsert( - keylet::ownerDir(uHighAccountID), sleRippleState->key(), describeOwnerDir(uHighAccountID)); - - if (!highNode) - return tecDIR_FULL; // LCOV_EXCL_LINE - - bool const bSetDst = saLimit.getIssuer() == uDstAccountID; - bool const bSetHigh = bSrcHigh ^ bSetDst; - - XRPL_ASSERT(sleAccount, "xrpl::trustCreate : non-null SLE"); - if (!sleAccount) - return tefINTERNAL; // LCOV_EXCL_LINE - - XRPL_ASSERT( - sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID), - "xrpl::trustCreate : matching account ID"); - auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID)); - if (!slePeer) - return tecNO_TARGET; - - // Remember deletion hints. - sleRippleState->setFieldU64(sfLowNode, *lowNode); - sleRippleState->setFieldU64(sfHighNode, *highNode); - - sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit); - sleRippleState->setFieldAmount( - bSetHigh ? sfLowLimit : sfHighLimit, - STAmount(Issue{saBalance.getCurrency(), bSetDst ? uSrcAccountID : uDstAccountID})); - - if (uQualityIn) - sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn); - - if (uQualityOut) - sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut); - - std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve; - - if (bAuth) - { - uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth); - } - if (bNoRipple) - { - uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple); - } - if (bFreeze) - { - uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze); - } - if (bDeepFreeze) - { - uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze); - } - - if ((slePeer->getFlags() & lsfDefaultRipple) == 0) - { - // The other side's default is no rippling - uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple); - } - - sleRippleState->setFieldU32(sfFlags, uFlags); - adjustOwnerCount(view, sleAccount, 1, j); - - // ONLY: Create ripple balance. - sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance); - - view.creditHook(uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed()); - - return tesSUCCESS; -} - -[[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - Issue const& issue, - beast::Journal journal) -{ - if (issue.native()) - { - auto const sle = view.read(keylet::account(accountID)); - if (!sle) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const balance = sle->getFieldAmount(sfBalance); - if (balance.xrp() != 0) - return tecHAS_OBLIGATIONS; - - return tesSUCCESS; - } - - // `asset` is an IOU. - // 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::line(accountID, issue)); - if (!line) - return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND; - if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::zero) - return tecHAS_OBLIGATIONS; - - // Adjust the owner count(s) - if (line->isFlag(lsfLowReserve)) - { - // Clear reserve for low account. - auto sleLowAccount = view.peek(keylet::account(line->at(sfLowLimit)->getIssuer())); - if (!sleLowAccount) - return tecINTERNAL; // LCOV_EXCL_LINE - - adjustOwnerCount(view, sleLowAccount, -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); - } - - if (line->isFlag(lsfHighReserve)) - { - // Clear reserve for high account. - auto sleHighAccount = view.peek(keylet::account(line->at(sfHighLimit)->getIssuer())); - if (!sleHighAccount) - return tecINTERNAL; // LCOV_EXCL_LINE - - adjustOwnerCount(view, sleHighAccount, -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); - } - - return trustDelete( - view, line, line->at(sfLowLimit)->getIssuer(), line->at(sfHighLimit)->getIssuer(), journal); -} - -[[nodiscard]] TER -removeEmptyHolding( - ApplyView& view, - AccountID const& accountID, - MPTIssue const& mptIssue, - beast::Journal journal) -{ - // If the account is the issuer, then no token should exist. MPTs do not - // have the legacy ability to create such a situation, but check anyway. If - // 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)); - 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 - // balance, it can not just be deleted, because that will throw the issuance - // 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) - return tecHAS_OBLIGATIONS; - - return authorizeMPToken( - view, - {}, // priorBalance - mptID, - accountID, - journal, - tfMPTUnauthorize // flags - ); -} - -TER -trustDelete( - ApplyView& view, - std::shared_ptr const& sleRippleState, - AccountID const& uLowAccountID, - AccountID const& uHighAccountID, - beast::Journal j) -{ - // Detect legacy dirs. - std::uint64_t uLowNode = sleRippleState->getFieldU64(sfLowNode); - std::uint64_t uHighNode = sleRippleState->getFieldU64(sfHighNode); - - JLOG(j.trace()) << "trustDelete: Deleting ripple line: low"; - - if (!view.dirRemove(keylet::ownerDir(uLowAccountID), uLowNode, sleRippleState->key(), false)) - { - return tefBAD_LEDGER; // LCOV_EXCL_LINE - } - - JLOG(j.trace()) << "trustDelete: Deleting ripple line: high"; - - if (!view.dirRemove(keylet::ownerDir(uHighAccountID), uHighNode, sleRippleState->key(), false)) - { - return tefBAD_LEDGER; // LCOV_EXCL_LINE - } - - JLOG(j.trace()) << "trustDelete: Deleting ripple line: state"; - view.erase(sleRippleState); - - return tesSUCCESS; -} - -TER -offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j) -{ - if (!sle) - return tesSUCCESS; - auto offerIndex = sle->key(); - auto owner = sle->getAccountID(sfAccount); - - // Detect legacy directories. - uint256 uDirectory = sle->getFieldH256(sfBookDirectory); - - if (!view.dirRemove(keylet::ownerDir(owner), sle->getFieldU64(sfOwnerNode), offerIndex, false)) - { - return tefBAD_LEDGER; // LCOV_EXCL_LINE - } - - if (!view.dirRemove(keylet::page(uDirectory), sle->getFieldU64(sfBookNode), offerIndex, false)) - { - return tefBAD_LEDGER; // LCOV_EXCL_LINE - } - - if (sle->isFieldPresent(sfAdditionalBooks)) - { - XRPL_ASSERT( - sle->isFlag(lsfHybrid) && sle->isFieldPresent(sfDomainID), - "xrpl::offerDelete : should be a hybrid domain offer"); - - auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks); - - for (auto const& bookDir : additionalBookDirs) - { - auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory); - auto const& dirNode = bookDir.getFieldU64(sfBookNode); - - if (!view.dirRemove(keylet::page(dirIndex), dirNode, offerIndex, false)) - { - return tefBAD_LEDGER; // LCOV_EXCL_LINE - } - } - } - - adjustOwnerCount(view, view.peek(keylet::account(owner)), -1, j); - - view.erase(sle); - - return tesSUCCESS; -} - -// Direct send w/o fees: -// - Redeeming IOUs and/or sending sender's own IOUs. -// - Create trust line if needed. -// --> bCheckIssuer : normally require issuer to be involved. -static TER -rippleCreditIOU( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - bool bCheckIssuer, - beast::Journal j) -{ - AccountID const& issuer = saAmount.getIssuer(); - Currency const& currency = saAmount.getCurrency(); - - // Make sure issuer is involved. - XRPL_ASSERT( - !bCheckIssuer || uSenderID == issuer || uReceiverID == issuer, - "xrpl::rippleCreditIOU : matching issuer or don't care"); - (void)issuer; - - // Disallow sending to self. - XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleCreditIOU : sender is not receiver"); - - bool const bSenderHigh = uSenderID > uReceiverID; - auto const index = keylet::line(uSenderID, uReceiverID, currency); - - XRPL_ASSERT( - !isXRP(uSenderID) && uSenderID != noAccount(), "xrpl::rippleCreditIOU : sender is not XRP"); - XRPL_ASSERT( - !isXRP(uReceiverID) && uReceiverID != noAccount(), - "xrpl::rippleCreditIOU : receiver is not XRP"); - - // If the line exists, modify it accordingly. - if (auto const sleRippleState = view.peek(index)) - { - STAmount saBalance = sleRippleState->getFieldAmount(sfBalance); - - if (bSenderHigh) - saBalance.negate(); // Put balance in sender terms. - - view.creditHook(uSenderID, uReceiverID, saAmount, saBalance); - - STAmount const saBefore = saBalance; - - saBalance -= saAmount; - - JLOG(j.trace()) << "rippleCreditIOU: " << to_string(uSenderID) << " -> " - << to_string(uReceiverID) << " : before=" << saBefore.getFullText() - << " amount=" << saAmount.getFullText() - << " after=" << saBalance.getFullText(); - - std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags)); - bool bDelete = false; - - // FIXME This NEEDS to be cleaned up and simplified. It's impossible - // for anyone to understand. - if (saBefore > beast::zero - // Sender balance was positive. - && saBalance <= beast::zero - // Sender is zero or negative. - && (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) - // Sender reserve is set. - && static_cast(uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != - static_cast( - view.read(keylet::account(uSenderID))->getFlags() & lsfDefaultRipple) && - !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && - !sleRippleState->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) - // Sender trust limit is 0. - && !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) - // Sender quality in is 0. - && !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) - // Sender quality out is 0. - { - // Clear the reserve of the sender, possibly delete the line! - adjustOwnerCount(view, view.peek(keylet::account(uSenderID)), -1, j); - - // Clear reserve flag. - sleRippleState->setFieldU32( - sfFlags, uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); - - // Balance is zero, receiver reserve is clear. - bDelete = !saBalance // Balance is zero. - && !(uFlags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)); - // Receiver reserve is clear. - } - - if (bSenderHigh) - saBalance.negate(); - - // Want to reflect balance to zero even if we are deleting line. - sleRippleState->setFieldAmount(sfBalance, saBalance); - // ONLY: Adjust ripple balance. - - if (bDelete) - { - return trustDelete( - view, - sleRippleState, - bSenderHigh ? uReceiverID : uSenderID, - !bSenderHigh ? uReceiverID : uSenderID, - j); - } - - view.update(sleRippleState); - return tesSUCCESS; - } - - STAmount const saReceiverLimit(Issue{currency, uReceiverID}); - STAmount saBalance{saAmount}; - - saBalance.setIssuer(noAccount()); - - JLOG(j.debug()) << "rippleCreditIOU: " - "create line: " - << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : " - << saAmount.getFullText(); - - auto const sleAccount = view.peek(keylet::account(uReceiverID)); - if (!sleAccount) - return tefINTERNAL; // LCOV_EXCL_LINE - - bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0; - - return trustCreate( - view, - bSenderHigh, - uSenderID, - uReceiverID, - index.key, - sleAccount, - false, - noRipple, - false, - false, - saBalance, - saReceiverLimit, - 0, - 0, - j); -} - -// Send regardless of limits. -// --> saAmount: Amount/currency/issuer to deliver to receiver. -// <-- saActual: Amount actually cost. Sender pays fees. -static TER -rippleSendIOU( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - STAmount& saActual, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - auto const& issuer = saAmount.getIssuer(); - - XRPL_ASSERT( - !isXRP(uSenderID) && !isXRP(uReceiverID), - "xrpl::rippleSendIOU : neither sender nor receiver is XRP"); - XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleSendIOU : sender is not receiver"); - - if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount()) - { - // Direct send: redeeming IOUs and/or sending own IOUs. - auto const ter = rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, false, j); - if (!isTesSuccess(ter)) - return ter; - saActual = saAmount; - return tesSUCCESS; - } - - // Sending 3rd party IOUs: transit. - - // Calculate the amount to transfer accounting - // for any transfer fees if the fee is not waived: - saActual = (waiveFee == WaiveTransferFee::Yes) ? saAmount - : multiply(saAmount, transferRate(view, issuer)); - - JLOG(j.debug()) << "rippleSendIOU> " << to_string(uSenderID) << " - > " - << to_string(uReceiverID) << " : deliver=" << saAmount.getFullText() - << " cost=" << saActual.getFullText(); - - TER terResult = rippleCreditIOU(view, issuer, uReceiverID, saAmount, true, j); - - if (tesSUCCESS == terResult) - terResult = rippleCreditIOU(view, uSenderID, issuer, saActual, true, j); - - return terResult; -} - -// Send regardless of limits. -// --> receivers: Amount/currency/issuer to deliver to receivers. -// <-- saActual: Amount actually cost to sender. Sender pays fees. -static TER -rippleSendMultiIOU( - ApplyView& view, - AccountID const& senderID, - Issue const& issue, - MultiplePaymentDestinations const& receivers, - STAmount& actual, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - auto const& issuer = issue.getIssuer(); - - XRPL_ASSERT(!isXRP(senderID), "xrpl::rippleSendMultiIOU : sender is not XRP"); - - // These may diverge - STAmount takeFromSender{issue}; - actual = takeFromSender; - - // Failures return immediately. - for (auto const& r : receivers) - { - auto const& receiverID = r.first; - STAmount amount{issue, r.second}; - - /* If we aren't sending anything or if the sender is the same as the - * receiver then we don't need to do anything. - */ - if (!amount || (senderID == receiverID)) - continue; - - XRPL_ASSERT(!isXRP(receiverID), "xrpl::rippleSendMultiIOU : receiver is not XRP"); - - if (senderID == issuer || receiverID == issuer || issuer == noAccount()) - { - // Direct send: redeeming IOUs and/or sending own IOUs. - if (auto const ter = rippleCreditIOU(view, senderID, receiverID, amount, false, j)) - return ter; - actual += amount; - // Do not add amount to takeFromSender, because rippleCreditIOU took - // it. - - continue; - } - - // Sending 3rd party IOUs: transit. - - // Calculate the amount to transfer accounting - // for any transfer fees if the fee is not waived: - STAmount actualSend = (waiveFee == WaiveTransferFee::Yes) - ? amount - : multiply(amount, transferRate(view, issuer)); - actual += actualSend; - takeFromSender += actualSend; - - JLOG(j.debug()) << "rippleSendMultiIOU> " << to_string(senderID) << " - > " - << to_string(receiverID) << " : deliver=" << amount.getFullText() - << " cost=" << actual.getFullText(); - - if (TER const terResult = rippleCreditIOU(view, issuer, receiverID, amount, true, j)) - return terResult; - } - - if (senderID != issuer && takeFromSender) - { - if (TER const terResult = rippleCreditIOU(view, senderID, issuer, takeFromSender, true, j)) - return terResult; - } - - return tesSUCCESS; -} - -static TER -accountSendIOU( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - if (view.rules().enabled(fixAMMv1_1)) - { - if (saAmount < beast::zero || saAmount.holds()) - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - } - else - { - // LCOV_EXCL_START - XRPL_ASSERT( - saAmount >= beast::zero && !saAmount.holds(), - "xrpl::accountSendIOU : minimum amount and not MPT"); - // LCOV_EXCL_STOP - } - - /* If we aren't sending anything or if the sender is the same as the - * receiver then we don't need to do anything. - */ - if (!saAmount || (uSenderID == uReceiverID)) - return tesSUCCESS; - - if (!saAmount.native()) - { - STAmount saActual; - - JLOG(j.trace()) << "accountSendIOU: " << to_string(uSenderID) << " -> " - << to_string(uReceiverID) << " : " << saAmount.getFullText(); - - return rippleSendIOU(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); - } - - /* XRP send which does not check reserve and can do pure adjustment. - * Note that sender or receiver may be null and this not a mistake; this - * setup is used during pathfinding and it is carefully controlled to - * ensure that transfers are balanced. - */ - TER terResult(tesSUCCESS); - - SLE::pointer sender = - uSenderID != beast::zero ? view.peek(keylet::account(uSenderID)) : SLE::pointer(); - SLE::pointer receiver = - uReceiverID != beast::zero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer(); - - if (auto stream = j.trace()) - { - std::string sender_bal("-"); - std::string receiver_bal("-"); - - if (sender) - sender_bal = sender->getFieldAmount(sfBalance).getFullText(); - - if (receiver) - receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - - stream << "accountSendIOU> " << to_string(uSenderID) << " (" << sender_bal << ") -> " - << to_string(uReceiverID) << " (" << receiver_bal - << ") : " << saAmount.getFullText(); - } - - if (sender) - { - if (sender->getFieldAmount(sfBalance) < saAmount) - { - // VFALCO Its laborious to have to mutate the - // TER based on params everywhere - // LCOV_EXCL_START - terResult = view.open() ? TER{telFAILED_PROCESSING} : TER{tecFAILED_PROCESSING}; - // LCOV_EXCL_STOP - } - else - { - auto const sndBal = sender->getFieldAmount(sfBalance); - view.creditHook(uSenderID, xrpAccount(), saAmount, sndBal); - - // Decrement XRP balance. - sender->setFieldAmount(sfBalance, sndBal - saAmount); - view.update(sender); - } - } - - if (tesSUCCESS == terResult && receiver) - { - // Increment XRP balance. - auto const rcvBal = receiver->getFieldAmount(sfBalance); - receiver->setFieldAmount(sfBalance, rcvBal + saAmount); - view.creditHook(xrpAccount(), uReceiverID, saAmount, -rcvBal); - - view.update(receiver); - } - - if (auto stream = j.trace()) - { - std::string sender_bal("-"); - std::string receiver_bal("-"); - - if (sender) - sender_bal = sender->getFieldAmount(sfBalance).getFullText(); - - if (receiver) - receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - - stream << "accountSendIOU< " << to_string(uSenderID) << " (" << sender_bal << ") -> " - << to_string(uReceiverID) << " (" << receiver_bal - << ") : " << saAmount.getFullText(); - } - - return terResult; -} - -static TER -accountSendMultiIOU( - ApplyView& view, - AccountID const& senderID, - Issue const& issue, - MultiplePaymentDestinations const& receivers, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - XRPL_ASSERT_PARTS( - receivers.size() > 1, "xrpl::accountSendMultiIOU", "multiple recipients provided"); - - if (!issue.native()) - { - STAmount actual; - JLOG(j.trace()) << "accountSendMultiIOU: " << to_string(senderID) << " sending " - << receivers.size() << " IOUs"; - - return rippleSendMultiIOU(view, senderID, issue, receivers, actual, j, waiveFee); - } - - /* XRP send which does not check reserve and can do pure adjustment. - * Note that sender or receiver may be null and this not a mistake; this - * setup could be used during pathfinding and it is carefully controlled to - * ensure that transfers are balanced. - */ - - SLE::pointer sender = - senderID != beast::zero ? view.peek(keylet::account(senderID)) : SLE::pointer(); - - if (auto stream = j.trace()) - { - std::string sender_bal("-"); - - if (sender) - sender_bal = sender->getFieldAmount(sfBalance).getFullText(); - - stream << "accountSendMultiIOU> " << to_string(senderID) << " (" << sender_bal << ") -> " - << receivers.size() << " receivers."; - } - - // Failures return immediately. - STAmount takeFromSender{issue}; - for (auto const& r : receivers) - { - auto const& receiverID = r.first; - STAmount amount{issue, r.second}; - - if (amount < beast::zero) - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - - /* If we aren't sending anything or if the sender is the same as the - * receiver then we don't need to do anything. - */ - if (!amount || (senderID == receiverID)) - continue; - - SLE::pointer receiver = - receiverID != beast::zero ? view.peek(keylet::account(receiverID)) : SLE::pointer(); - - if (auto stream = j.trace()) - { - std::string receiver_bal("-"); - - if (receiver) - receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - - stream << "accountSendMultiIOU> " << to_string(senderID) << " -> " - << to_string(receiverID) << " (" << receiver_bal - << ") : " << amount.getFullText(); - } - - if (receiver) - { - // Increment XRP balance. - auto const rcvBal = receiver->getFieldAmount(sfBalance); - receiver->setFieldAmount(sfBalance, rcvBal + amount); - view.creditHook(xrpAccount(), receiverID, amount, -rcvBal); - - view.update(receiver); - - // Take what is actually sent - takeFromSender += amount; - } - - if (auto stream = j.trace()) - { - std::string receiver_bal("-"); - - if (receiver) - receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - - stream << "accountSendMultiIOU< " << to_string(senderID) << " -> " - << to_string(receiverID) << " (" << receiver_bal - << ") : " << amount.getFullText(); - } - } - - if (sender) - { - if (sender->getFieldAmount(sfBalance) < takeFromSender) - { - return TER{tecFAILED_PROCESSING}; - } - - auto const sndBal = sender->getFieldAmount(sfBalance); - view.creditHook(senderID, xrpAccount(), takeFromSender, sndBal); - - // Decrement XRP balance. - sender->setFieldAmount(sfBalance, sndBal - takeFromSender); - view.update(sender); - } - - if (auto stream = j.trace()) - { - std::string sender_bal("-"); - - if (sender) - sender_bal = sender->getFieldAmount(sfBalance).getFullText(); - - stream << "accountSendMultiIOU< " << to_string(senderID) << " (" << sender_bal << ") -> " - << receivers.size() << " receivers."; - } - return tesSUCCESS; -} - -static TER -rippleCreditMPT( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - beast::Journal j) -{ - // Do not check MPT authorization here - it must have been checked earlier - auto const mptID = keylet::mptIssuance(saAmount.get().getMptID()); - auto const& issuer = saAmount.getIssuer(); - auto sleIssuance = view.peek(mptID); - if (!sleIssuance) - return tecOBJECT_NOT_FOUND; - if (uSenderID == issuer) - { - (*sleIssuance)[sfOutstandingAmount] += saAmount.mpt().value(); - view.update(sleIssuance); - } - else - { - auto const mptokenID = keylet::mptoken(mptID.key, uSenderID); - if (auto sle = view.peek(mptokenID)) - { - auto const amt = sle->getFieldU64(sfMPTAmount); - auto const pay = saAmount.mpt().value(); - if (amt < pay) - return tecINSUFFICIENT_FUNDS; - (*sle)[sfMPTAmount] = amt - pay; - view.update(sle); - } - else - { - return tecNO_AUTH; - } - } - - if (uReceiverID == issuer) - { - auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); - auto const redeem = saAmount.mpt().value(); - if (outstanding >= redeem) - { - sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem); - view.update(sleIssuance); - } - else - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - } - else - { - auto const mptokenID = keylet::mptoken(mptID.key, uReceiverID); - if (auto sle = view.peek(mptokenID)) - { - (*sle)[sfMPTAmount] += saAmount.mpt().value(); - view.update(sle); - } - else - { - return tecNO_AUTH; - } - } - - return tesSUCCESS; -} - -static TER -rippleSendMPT( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - STAmount& saActual, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleSendMPT : sender is not receiver"); - - // Safe to get MPT since rippleSendMPT is only called by accountSendMPT - auto const& issuer = saAmount.getIssuer(); - - auto const sle = view.read(keylet::mptIssuance(saAmount.get().getMptID())); - if (!sle) - return tecOBJECT_NOT_FOUND; - - if (uSenderID == issuer || uReceiverID == issuer) - { - // if sender is issuer, check that the new OutstandingAmount will not - // exceed MaximumAmount - if (uSenderID == issuer) - { - auto const sendAmount = saAmount.mpt().value(); - auto const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); - if (sendAmount > maximumAmount || - sle->getFieldU64(sfOutstandingAmount) > maximumAmount - sendAmount) - return tecPATH_DRY; - } - - // Direct send: redeeming MPTs and/or sending own MPTs. - auto const ter = rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); - if (!isTesSuccess(ter)) - return ter; - saActual = saAmount; - return tesSUCCESS; - } - - // Sending 3rd party MPTs: transit. - saActual = (waiveFee == WaiveTransferFee::Yes) - ? saAmount - : multiply(saAmount, transferRate(view, saAmount.get().getMptID())); - - JLOG(j.debug()) << "rippleSendMPT> " << to_string(uSenderID) << " - > " - << to_string(uReceiverID) << " : deliver=" << saAmount.getFullText() - << " cost=" << saActual.getFullText(); - - if (auto const terResult = rippleCreditMPT(view, issuer, uReceiverID, saAmount, j); - !isTesSuccess(terResult)) - return terResult; - - return rippleCreditMPT(view, uSenderID, issuer, saActual, j); -} - -static TER -rippleSendMultiMPT( - ApplyView& view, - AccountID const& senderID, - MPTIssue const& mptIssue, - MultiplePaymentDestinations const& receivers, - STAmount& actual, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - // Safe to get MPT since rippleSendMultiMPT is only called by - // accountSendMultiMPT - auto const& issuer = mptIssue.getIssuer(); - - auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID())); - if (!sle) - return tecOBJECT_NOT_FOUND; - - // These may diverge - STAmount takeFromSender{mptIssue}; - actual = takeFromSender; - - for (auto const& r : receivers) - { - auto const& receiverID = r.first; - STAmount amount{mptIssue, r.second}; - - if (amount < beast::zero) - { - return tecINTERNAL; // LCOV_EXCL_LINE - } - - /* If we aren't sending anything or if the sender is the same as the - * receiver then we don't need to do anything. - */ - if (!amount || (senderID == receiverID)) - continue; - - if (senderID == issuer || receiverID == issuer) - { - // if sender is issuer, check that the new OutstandingAmount will - // not exceed MaximumAmount - if (senderID == issuer) - { - XRPL_ASSERT_PARTS( - takeFromSender == beast::zero, - "rippler::rippleSendMultiMPT", - "sender == issuer, takeFromSender == zero"); - auto const sendAmount = amount.mpt().value(); - auto const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); - if (sendAmount > maximumAmount || - sle->getFieldU64(sfOutstandingAmount) > maximumAmount - sendAmount) - return tecPATH_DRY; - } - - // Direct send: redeeming MPTs and/or sending own MPTs. - if (auto const ter = rippleCreditMPT(view, senderID, receiverID, amount, j)) - return ter; - actual += amount; - // Do not add amount to takeFromSender, because rippleCreditMPT took - // it - - continue; - } - - // Sending 3rd party MPTs: transit. - STAmount actualSend = (waiveFee == WaiveTransferFee::Yes) - ? amount - : multiply(amount, transferRate(view, amount.get().getMptID())); - actual += actualSend; - takeFromSender += actualSend; - - JLOG(j.debug()) << "rippleSendMultiMPT> " << to_string(senderID) << " - > " - << to_string(receiverID) << " : deliver=" << amount.getFullText() - << " cost=" << actualSend.getFullText(); - - if (auto const terResult = rippleCreditMPT(view, issuer, receiverID, amount, j)) - return terResult; - } - if (senderID != issuer && takeFromSender) - { - if (TER const terResult = rippleCreditMPT(view, senderID, issuer, takeFromSender, j)) - return terResult; - } - - return tesSUCCESS; -} - -static TER -accountSendMPT( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - XRPL_ASSERT( - saAmount >= beast::zero && saAmount.holds(), - "xrpl::accountSendMPT : minimum amount and MPT"); - - /* If we aren't sending anything or if the sender is the same as the - * receiver then we don't need to do anything. - */ - if (!saAmount || (uSenderID == uReceiverID)) - return tesSUCCESS; - - STAmount saActual{saAmount.asset()}; - - return rippleSendMPT(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); -} - -static TER -accountSendMultiMPT( - ApplyView& view, - AccountID const& senderID, - MPTIssue const& mptIssue, - MultiplePaymentDestinations const& receivers, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - STAmount actual; - - return rippleSendMultiMPT(view, senderID, mptIssue, receivers, actual, j, waiveFee); -} - -TER -accountSend( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - return std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - { - return accountSendIOU(view, uSenderID, uReceiverID, saAmount, j, waiveFee); - } - else - { - return accountSendMPT(view, uSenderID, uReceiverID, saAmount, j, waiveFee); - } - }, - saAmount.asset().value()); -} - -TER -accountSendMulti( - ApplyView& view, - AccountID const& senderID, - Asset const& asset, - MultiplePaymentDestinations const& receivers, - beast::Journal j, - WaiveTransferFee waiveFee) -{ - XRPL_ASSERT_PARTS( - receivers.size() > 1, "xrpl::accountSendMulti", "multiple recipients provided"); - return std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - { - return accountSendMultiIOU(view, senderID, issue, receivers, j, waiveFee); - } - else - { - return accountSendMultiMPT(view, senderID, issue, receivers, j, waiveFee); - } - }, - asset.value()); -} - -static bool -updateTrustLine( - ApplyView& view, - SLE::pointer state, - bool bSenderHigh, - AccountID const& sender, - STAmount const& before, - STAmount const& after, - beast::Journal j) -{ - if (!state) - return false; - std::uint32_t const flags(state->getFieldU32(sfFlags)); - - auto sle = view.peek(keylet::account(sender)); - if (!sle) - return false; - - // YYY Could skip this if rippling in reverse. - if (before > beast::zero - // Sender balance was positive. - && after <= beast::zero - // Sender is zero or negative. - && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) - // Sender reserve is set. - && static_cast(flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != - static_cast(sle->getFlags() & lsfDefaultRipple) && - !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && - !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) - // Sender trust limit is 0. - && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) - // Sender quality in is 0. - && !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) - // Sender quality out is 0. - { - // VFALCO Where is the line being deleted? - // Clear the reserve of the sender, possibly delete the line! - adjustOwnerCount(view, sle, -1, j); - - // Clear reserve flag. - state->setFieldU32(sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); - - // Balance is zero, receiver reserve is clear. - if (!after // Balance is zero. - && !(flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve))) - return true; - } - return false; -} - -TER -issueIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j) -{ - XRPL_ASSERT( - !isXRP(account) && !isXRP(issue.account), - "xrpl::issueIOU : neither account nor issuer is XRP"); - - // Consistency check - XRPL_ASSERT(issue == amount.issue(), "xrpl::issueIOU : matching issue"); - - // Can't send to self! - XRPL_ASSERT(issue.account != account, "xrpl::issueIOU : not issuer account"); - - JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": " << amount.getFullText(); - - bool bSenderHigh = issue.account > account; - - auto const index = keylet::line(issue.account, account, issue.currency); - - if (auto state = view.peek(index)) - { - STAmount final_balance = state->getFieldAmount(sfBalance); - - if (bSenderHigh) - final_balance.negate(); // Put balance in sender terms. - - STAmount const start_balance = final_balance; - - final_balance -= amount; - - auto const must_delete = updateTrustLine( - view, state, bSenderHigh, issue.account, start_balance, final_balance, j); - - view.creditHook(issue.account, account, amount, start_balance); - - if (bSenderHigh) - final_balance.negate(); - - // Adjust the balance on the trust line if necessary. We do this even if - // we are going to delete the line to reflect the correct balance at the - // time of deletion. - state->setFieldAmount(sfBalance, final_balance); - if (must_delete) - { - return trustDelete( - view, - state, - bSenderHigh ? account : issue.account, - bSenderHigh ? issue.account : account, - j); - } - - view.update(state); - - return tesSUCCESS; - } - - // NIKB TODO: The limit uses the receiver's account as the issuer and - // this is unnecessarily inefficient as copying which could be avoided - // is now required. Consider available options. - STAmount const limit(Issue{issue.currency, account}); - STAmount final_balance = amount; - - final_balance.setIssuer(noAccount()); - - auto const receiverAccount = view.peek(keylet::account(account)); - if (!receiverAccount) - return tefINTERNAL; // LCOV_EXCL_LINE - - bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0; - - return trustCreate( - view, - bSenderHigh, - issue.account, - account, - index.key, - receiverAccount, - false, - noRipple, - false, - false, - final_balance, - limit, - 0, - 0, - j); -} - -TER -redeemIOU( - ApplyView& view, - AccountID const& account, - STAmount const& amount, - Issue const& issue, - beast::Journal j) -{ - XRPL_ASSERT( - !isXRP(account) && !isXRP(issue.account), - "xrpl::redeemIOU : neither account nor issuer is XRP"); - - // Consistency check - XRPL_ASSERT(issue == amount.issue(), "xrpl::redeemIOU : matching issue"); - - // Can't send to self! - XRPL_ASSERT(issue.account != account, "xrpl::redeemIOU : not issuer account"); - - JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": " << amount.getFullText(); - - bool bSenderHigh = account > issue.account; - - if (auto state = view.peek(keylet::line(account, issue.account, issue.currency))) - { - STAmount final_balance = state->getFieldAmount(sfBalance); - - if (bSenderHigh) - final_balance.negate(); // Put balance in sender terms. - - STAmount const start_balance = final_balance; - - final_balance -= amount; - - auto const must_delete = - updateTrustLine(view, state, bSenderHigh, account, start_balance, final_balance, j); - - view.creditHook(account, issue.account, amount, start_balance); - - if (bSenderHigh) - final_balance.negate(); - - // Adjust the balance on the trust line if necessary. We do this even if - // we are going to delete the line to reflect the correct balance at the - // time of deletion. - state->setFieldAmount(sfBalance, final_balance); - - if (must_delete) - { - return trustDelete( - view, - state, - bSenderHigh ? issue.account : account, - bSenderHigh ? account : issue.account, - j); - } - - view.update(state); - return tesSUCCESS; - } - - // In order to hold an IOU, a trust line *MUST* exist to track the - // balance. If it doesn't, then something is very wrong. Don't try - // to continue. - // LCOV_EXCL_START - JLOG(j.fatal()) << "redeemIOU: " << to_string(account) << " attempts to redeem " - << amount.getFullText() << " but no trust line exists!"; - - return tefINTERNAL; - // LCOV_EXCL_STOP -} - -TER -transferXRP( - ApplyView& view, - AccountID const& from, - AccountID const& to, - STAmount const& amount, - beast::Journal j) -{ - XRPL_ASSERT(from != beast::zero, "xrpl::transferXRP : nonzero from account"); - XRPL_ASSERT(to != beast::zero, "xrpl::transferXRP : nonzero to account"); - XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver"); - XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP"); - - SLE::pointer const sender = view.peek(keylet::account(from)); - SLE::pointer const receiver = view.peek(keylet::account(to)); - if (!sender || !receiver) - return tefINTERNAL; // LCOV_EXCL_LINE - - JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> " << to_string(to) - << ") : " << amount.getFullText(); - - if (sender->getFieldAmount(sfBalance) < amount) - { - // VFALCO Its unfortunate we have to keep - // mutating these TER everywhere - // FIXME: this logic should be moved to callers maybe? - // LCOV_EXCL_START - return view.open() ? TER{telFAILED_PROCESSING} : TER{tecFAILED_PROCESSING}; - // LCOV_EXCL_STOP - } - - // Decrement XRP balance. - sender->setFieldAmount(sfBalance, sender->getFieldAmount(sfBalance) - amount); - view.update(sender); - - receiver->setFieldAmount(sfBalance, receiver->getFieldAmount(sfBalance) + amount); - view.update(receiver); - - return tesSUCCESS; -} - -TER -requireAuth(ReadView const& view, Issue const& issue, AccountID const& account, AuthType authType) -{ - if (isXRP(issue) || issue.account == account) - return tesSUCCESS; - - auto const trustLine = view.read(keylet::line(account, issue.account, issue.currency)); - // If account has no line, and this is a strong check, fail - if (!trustLine && authType == AuthType::StrongAuth) - return tecNO_LINE; - - // If this is a weak or legacy check, or if the account has a line, fail if - // auth is required and not set on the line - if (auto const issuerAccount = view.read(keylet::account(issue.account)); - issuerAccount && (*issuerAccount)[sfFlags] & lsfRequireAuth) - { - if (trustLine) - { - return ((*trustLine)[sfFlags] & ((account > issue.account) ? lsfLowAuth : lsfHighAuth)) - ? tesSUCCESS - : TER{tecNO_AUTH}; - } - return TER{tecNO_LINE}; - } - - return tesSUCCESS; -} - -TER -requireAuth( - ReadView const& view, - MPTIssue const& mptIssue, - AccountID const& account, - AuthType authType, - int depth) -{ - auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); - auto const sleIssuance = view.read(mptID); - if (!sleIssuance) - return tecOBJECT_NOT_FOUND; - - auto const mptIssuer = sleIssuance->getAccountID(sfIssuer); - - // issuer is always "authorized" - if (mptIssuer == account) // Issuer won't have MPToken - return tesSUCCESS; - - bool const featureSAVEnabled = view.rules().enabled(featureSingleAssetVault); - - if (featureSAVEnabled) - { - if (depth >= maxAssetCheckDepth) - return tecINTERNAL; // LCOV_EXCL_LINE - - // requireAuth is recursive if the issuer is a vault pseudo-account - auto const sleIssuer = view.read(keylet::account(mptIssuer)); - if (!sleIssuer) - return tefINTERNAL; // LCOV_EXCL_LINE - - if (sleIssuer->isFieldPresent(sfVaultID)) - { - auto const sleVault = view.read(keylet::vault(sleIssuer->getFieldH256(sfVaultID))); - if (!sleVault) - return tefINTERNAL; // LCOV_EXCL_LINE - - auto const asset = sleVault->at(sfAsset); - if (auto const err = std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - { - return requireAuth(view, issue, account, authType); - } - else - { - return requireAuth(view, issue, account, authType, depth + 1); - } - }, - asset.value()); - !isTesSuccess(err)) - return err; - } - } - - auto const mptokenID = keylet::mptoken(mptID.key, account); - auto const sleToken = view.read(mptokenID); - - // if account has no MPToken, fail - if (!sleToken && (authType == AuthType::StrongAuth || authType == AuthType::Legacy)) - return tecNO_AUTH; - - // Note, this check is not amendment-gated because DomainID will be always - // empty **unless** writing to it has been enabled by an amendment - auto const maybeDomainID = sleIssuance->at(~sfDomainID); - if (maybeDomainID) - { - XRPL_ASSERT( - sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth, - "xrpl::requireAuth : issuance requires authorization"); - // ter = tefINTERNAL | tecOBJECT_NOT_FOUND | tecNO_AUTH | tecEXPIRED - auto const ter = credentials::validDomain(view, *maybeDomainID, account); - if (isTesSuccess(ter)) - { - return ter; // Note: sleToken might be null - } - if (!sleToken) - { - return ter; - } - // We ignore error from validDomain if we found sleToken, as it could - // belong to someone who is explicitly authorized e.g. a vault owner. - } - - if (featureSAVEnabled) - { - // Implicitly authorize Vault and LoanBroker pseudo-accounts - if (isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID})) - return tesSUCCESS; - } - - // mptoken must be authorized if issuance enabled requireAuth - if (sleIssuance->isFlag(lsfMPTRequireAuth) && - (!sleToken || !sleToken->isFlag(lsfMPTAuthorized))) - return tecNO_AUTH; - - return tesSUCCESS; // Note: sleToken might be null -} - -[[nodiscard]] TER -enforceMPTokenAuthorization( - ApplyView& view, - MPTID const& mptIssuanceID, - AccountID const& account, - XRPAmount const& priorBalance, // for MPToken authorization - beast::Journal j) -{ - auto const sleIssuance = view.read(keylet::mptIssuance(mptIssuanceID)); - if (!sleIssuance) - return tefINTERNAL; // LCOV_EXCL_LINE - - XRPL_ASSERT( - sleIssuance->isFlag(lsfMPTRequireAuth), - "xrpl::enforceMPTokenAuthorization : authorization required"); - - if (account == sleIssuance->at(sfIssuer)) - return tefINTERNAL; // LCOV_EXCL_LINE - - auto const keylet = keylet::mptoken(mptIssuanceID, account); - auto const sleToken = view.read(keylet); // NOTE: might be null - auto const maybeDomainID = sleIssuance->at(~sfDomainID); - bool expired = false; - bool const authorizedByDomain = [&]() -> bool { - // NOTE: defensive here, should be checked in preclaim - if (!maybeDomainID.has_value()) - return false; // LCOV_EXCL_LINE - - auto const ter = verifyValidDomain(view, account, *maybeDomainID, j); - if (isTesSuccess(ter)) - return true; - if (ter == tecEXPIRED) - expired = true; - return false; - }(); - - if (!authorizedByDomain && sleToken == nullptr) - { - // Could not find MPToken and won't create one, could be either of: - // - // 1. Field sfDomainID not set in MPTokenIssuance or - // 2. Account has no matching and accepted credentials or - // 3. Account has all expired credentials (deleted in verifyValidDomain) - // - // Either way, return tecNO_AUTH and there is nothing else to do - return expired ? tecEXPIRED : tecNO_AUTH; - } - if (!authorizedByDomain && maybeDomainID.has_value()) - { - // Found an MPToken but the account is not authorized and we expect - // it to have been authorized by the domain. This could be because the - // credentials used to create the MPToken have expired or been deleted. - return expired ? tecEXPIRED : tecNO_AUTH; - } - if (!authorizedByDomain) - { - // We found an MPToken, but sfDomainID is not set, so this is a classic - // MPToken which requires authorization by the token issuer. - XRPL_ASSERT( - sleToken != nullptr && !maybeDomainID.has_value(), - "xrpl::enforceMPTokenAuthorization : found MPToken"); - if (sleToken->isFlag(lsfMPTAuthorized)) - return tesSUCCESS; - - return tecNO_AUTH; - } - if (authorizedByDomain && sleToken != nullptr) - { - // Found an MPToken, authorized by the domain. Ignore authorization flag - // lsfMPTAuthorized because it is meaningless. Return tesSUCCESS - XRPL_ASSERT( - maybeDomainID.has_value(), - "xrpl::enforceMPTokenAuthorization : found MPToken for domain"); - return tesSUCCESS; - } - if (authorizedByDomain) - { - // Could not find MPToken but there should be one because we are - // authorized by domain. Proceed to create it, then return tesSUCCESS - XRPL_ASSERT( - maybeDomainID.has_value() && sleToken == nullptr, - "xrpl::enforceMPTokenAuthorization : new MPToken for domain"); - if (auto const err = authorizeMPToken( - view, - priorBalance, // priorBalance - mptIssuanceID, // mptIssuanceID - account, // account - j); - !isTesSuccess(err)) - return err; - - return tesSUCCESS; - } - - // LCOV_EXCL_START - UNREACHABLE("xrpl::enforceMPTokenAuthorization : condition list is incomplete"); - return tefINTERNAL; - // LCOV_EXCL_STOP -} - -TER -canTransfer( - ReadView const& view, - MPTIssue const& mptIssue, - AccountID const& from, - AccountID const& to) -{ - auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); - auto const sleIssuance = view.read(mptID); - if (!sleIssuance) - return tecOBJECT_NOT_FOUND; - - if (!(sleIssuance->getFieldU32(sfFlags) & lsfMPTCanTransfer)) - { - if (from != (*sleIssuance)[sfIssuer] && to != (*sleIssuance)[sfIssuer]) - return TER{tecNO_AUTH}; - } - return tesSUCCESS; -} - -[[nodiscard]] TER -canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to) -{ - if (issue.native()) - return tesSUCCESS; - - auto const& issuerId = issue.getIssuer(); - if (issuerId == from || issuerId == to) - return tesSUCCESS; - auto const sleIssuer = view.read(keylet::account(issuerId)); - if (sleIssuer == nullptr) - return tefINTERNAL; // LCOV_EXCL_LINE - - auto const isRippleDisabled = [&](AccountID account) -> bool { - // Line might not exist, but some transfers can create it. If this - // is the case, just check the default ripple on the issuer account. - auto const line = view.read(keylet::line(account, issue)); - if (line) - { - bool const issuerHigh = issuerId > account; - return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple); - } - return sleIssuer->isFlag(lsfDefaultRipple) == false; - }; - - // Fail if rippling disabled on both trust lines - if (isRippleDisabled(from) && isRippleDisabled(to)) - return terNO_RIPPLE; - - return tesSUCCESS; -} - TER cleanupOnAccountDelete( ApplyView& view, @@ -3234,7 +469,7 @@ cleanupOnAccountDelete( { // Directory node has an invalid index. Bail out. // LCOV_EXCL_START - JLOG(j.fatal()) << "AccountDelete: Directory node in ledger " << view.seq() + JLOG(j.fatal()) << "DeleteAccount: Directory node in ledger " << view.seq() << " has index to object that is missing: " << to_string(dirEntry); return tefBAD_LEDGER; // LCOV_EXCL_STOP @@ -3269,7 +504,7 @@ cleanupOnAccountDelete( if (uDirEntry == 0) { // LCOV_EXCL_START - JLOG(j.error()) << "AccountDelete iterator re-validation failed."; + JLOG(j.error()) << "DeleteAccount iterator re-validation failed."; return tefBAD_LEDGER; // LCOV_EXCL_STOP } @@ -3282,447 +517,6 @@ cleanupOnAccountDelete( return tesSUCCESS; } -TER -deleteAMMTrustLine( - ApplyView& view, - std::shared_ptr sleState, - std::optional const& ammAccountID, - beast::Journal j) -{ - if (!sleState || sleState->getType() != ltRIPPLE_STATE) - return tecINTERNAL; // LCOV_EXCL_LINE - - auto const& [low, high] = std::minmax( - sleState->getFieldAmount(sfLowLimit).getIssuer(), - sleState->getFieldAmount(sfHighLimit).getIssuer()); - auto sleLow = view.peek(keylet::account(low)); - auto sleHigh = view.peek(keylet::account(high)); - if (!sleLow || !sleHigh) - return tecINTERNAL; // LCOV_EXCL_LINE - - bool const ammLow = sleLow->isFieldPresent(sfAMMID); - bool const ammHigh = sleHigh->isFieldPresent(sfAMMID); - - // can't both be AMM - if (ammLow && ammHigh) - return tecINTERNAL; // LCOV_EXCL_LINE - - // at least one must be - if (!ammLow && !ammHigh) - return terNO_AMM; - - // one must be the target amm - if (ammAccountID && (low != *ammAccountID && high != *ammAccountID)) - return terNO_AMM; - - if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter)) - { - JLOG(j.error()) << "deleteAMMTrustLine: failed to delete the trustline."; - return ter; - } - - auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve; - if (!(sleState->getFlags() & uFlags)) - return tecINTERNAL; // LCOV_EXCL_LINE - - adjustOwnerCount(view, !ammLow ? sleLow : sleHigh, -1, j); - - return tesSUCCESS; -} - -TER -rippleCredit( - ApplyView& view, - AccountID const& uSenderID, - AccountID const& uReceiverID, - STAmount const& saAmount, - bool bCheckIssuer, - beast::Journal j) -{ - return std::visit( - [&](TIss const& issue) { - if constexpr (std::is_same_v) - { - return rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j); - } - else - { - XRPL_ASSERT(!bCheckIssuer, "xrpl::rippleCredit : not checking issuer"); - return rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); - } - }, - saAmount.asset().value()); -} - -[[nodiscard]] std::optional -assetsToSharesDeposit( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& assets) -{ - XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets"); - XRPL_ASSERT( - assets.asset() == vault->at(sfAsset), - "xrpl::assetsToSharesDeposit : assets and vault match"); - if (assets.negative() || assets.asset() != vault->at(sfAsset)) - return std::nullopt; // LCOV_EXCL_LINE - - Number const assetTotal = vault->at(sfAssetsTotal); - STAmount shares{vault->at(sfShareMPTID)}; - if (assetTotal == 0) - { - return STAmount{ - shares.asset(), - Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)).truncate()}; - } - - Number const shareTotal = issuance->at(sfOutstandingAmount); - shares = ((shareTotal * assets) / assetTotal).truncate(); - return shares; -} - -[[nodiscard]] std::optional -sharesToAssetsDeposit( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& shares) -{ - XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares"); - XRPL_ASSERT( - shares.asset() == vault->at(sfShareMPTID), - "xrpl::sharesToAssetsDeposit : shares and vault match"); - if (shares.negative() || shares.asset() != vault->at(sfShareMPTID)) - return std::nullopt; // LCOV_EXCL_LINE - - Number const assetTotal = vault->at(sfAssetsTotal); - STAmount assets{vault->at(sfAsset)}; - if (assetTotal == 0) - { - return STAmount{ - assets.asset(), shares.mantissa(), shares.exponent() - vault->at(sfScale), false}; - } - - Number const shareTotal = issuance->at(sfOutstandingAmount); - assets = (assetTotal * shares) / shareTotal; - return assets; -} - -[[nodiscard]] std::optional -assetsToSharesWithdraw( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& assets, - TruncateShares truncate) -{ - XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets"); - XRPL_ASSERT( - assets.asset() == vault->at(sfAsset), - "xrpl::assetsToSharesWithdraw : assets and vault match"); - if (assets.negative() || assets.asset() != vault->at(sfAsset)) - return std::nullopt; // LCOV_EXCL_LINE - - Number assetTotal = vault->at(sfAssetsTotal); - assetTotal -= vault->at(sfLossUnrealized); - STAmount shares{vault->at(sfShareMPTID)}; - if (assetTotal == 0) - return shares; - Number const shareTotal = issuance->at(sfOutstandingAmount); - Number result = (shareTotal * assets) / assetTotal; - if (truncate == TruncateShares::yes) - result = result.truncate(); - shares = result; - return shares; -} - -[[nodiscard]] std::optional -sharesToAssetsWithdraw( - std::shared_ptr const& vault, - std::shared_ptr const& issuance, - STAmount const& shares) -{ - XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares"); - XRPL_ASSERT( - shares.asset() == vault->at(sfShareMPTID), - "xrpl::sharesToAssetsWithdraw : shares and vault match"); - if (shares.negative() || shares.asset() != vault->at(sfShareMPTID)) - return std::nullopt; // LCOV_EXCL_LINE - - Number assetTotal = vault->at(sfAssetsTotal); - assetTotal -= vault->at(sfLossUnrealized); - STAmount assets{vault->at(sfAsset)}; - if (assetTotal == 0) - return assets; - Number const shareTotal = issuance->at(sfOutstandingAmount); - assets = (assetTotal * shares) / shareTotal; - return assets; -} - -TER -rippleLockEscrowMPT( - ApplyView& view, - AccountID const& sender, - STAmount const& amount, - beast::Journal j) -{ - auto const mptIssue = amount.get(); - auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); - auto sleIssuance = view.peek(mptID); - if (!sleIssuance) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: MPT issuance not found for " - << mptIssue.getMptID(); - return tecOBJECT_NOT_FOUND; - } // LCOV_EXCL_STOP - - if (amount.getIssuer() == sender) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: sender is the issuer, cannot lock MPTs."; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - // 1. Decrease the MPT Holder MPTAmount - // 2. Increase the MPT Holder EscrowedAmount - { - auto const mptokenID = keylet::mptoken(mptID.key, sender); - auto sle = view.peek(mptokenID); - if (!sle) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: MPToken not found for " << sender; - return tecOBJECT_NOT_FOUND; - } // LCOV_EXCL_STOP - - auto const amt = sle->getFieldU64(sfMPTAmount); - auto const pay = amount.mpt().value(); - - // Underflow check for subtraction - if (!canSubtract(STAmount(mptIssue, amt), STAmount(mptIssue, pay))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: insufficient MPTAmount for " - << to_string(sender) << ": " << amt << " < " << pay; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - (*sle)[sfMPTAmount] = amt - pay; - - // Overflow check for addition - uint64_t const locked = (*sle)[~sfLockedAmount].value_or(0); - - if (!canAdd(STAmount(mptIssue, locked), STAmount(mptIssue, pay))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: overflow on locked amount for " - << to_string(sender) << ": " << locked << " + " << pay; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - if (sle->isFieldPresent(sfLockedAmount)) - { - (*sle)[sfLockedAmount] += pay; - } - else - { - sle->setFieldU64(sfLockedAmount, pay); - } - - view.update(sle); - } - - // 1. Increase the Issuance EscrowedAmount - // 2. DO NOT change the Issuance OutstandingAmount - { - uint64_t const issuanceEscrowed = (*sleIssuance)[~sfLockedAmount].value_or(0); - auto const pay = amount.mpt().value(); - - // Overflow check for addition - if (!canAdd(STAmount(mptIssue, issuanceEscrowed), STAmount(mptIssue, pay))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleLockEscrowMPT: overflow on issuance " - "locked amount for " - << mptIssue.getMptID() << ": " << issuanceEscrowed << " + " << pay; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - if (sleIssuance->isFieldPresent(sfLockedAmount)) - { - (*sleIssuance)[sfLockedAmount] += pay; - } - else - { - sleIssuance->setFieldU64(sfLockedAmount, pay); - } - - view.update(sleIssuance); - } - return tesSUCCESS; -} - -TER -rippleUnlockEscrowMPT( - ApplyView& view, - AccountID const& sender, - AccountID const& receiver, - STAmount const& netAmount, - STAmount const& grossAmount, - beast::Journal j) -{ - if (!view.rules().enabled(fixTokenEscrowV1)) - { - XRPL_ASSERT( - netAmount == grossAmount, "xrpl::rippleUnlockEscrowMPT : netAmount == grossAmount"); - } - - auto const& issuer = netAmount.getIssuer(); - auto const& mptIssue = netAmount.get(); - auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); - auto sleIssuance = view.peek(mptID); - if (!sleIssuance) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: MPT issuance not found for " - << mptIssue.getMptID(); - return tecOBJECT_NOT_FOUND; - } // LCOV_EXCL_STOP - - // Decrease the Issuance EscrowedAmount - { - if (!sleIssuance->isFieldPresent(sfLockedAmount)) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in issuance for " - << mptIssue.getMptID(); - return tecINTERNAL; - } // LCOV_EXCL_STOP - - auto const locked = sleIssuance->getFieldU64(sfLockedAmount); - auto const redeem = grossAmount.mpt().value(); - - // Underflow check for subtraction - if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, redeem))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " - << mptIssue.getMptID() << ": " << locked << " < " << redeem; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - auto const newLocked = locked - redeem; - if (newLocked == 0) - { - sleIssuance->makeFieldAbsent(sfLockedAmount); - } - else - { - sleIssuance->setFieldU64(sfLockedAmount, newLocked); - } - view.update(sleIssuance); - } - - if (issuer != receiver) - { - // Increase the MPT Holder MPTAmount - auto const mptokenID = keylet::mptoken(mptID.key, receiver); - auto sle = view.peek(mptokenID); - if (!sle) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << receiver; - return tecOBJECT_NOT_FOUND; - } // LCOV_EXCL_STOP - - auto current = sle->getFieldU64(sfMPTAmount); - auto delta = netAmount.mpt().value(); - - // Overflow check for addition - if (!canAdd(STAmount(mptIssue, current), STAmount(mptIssue, delta))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: overflow on MPTAmount for " - << to_string(receiver) << ": " << current << " + " << delta; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - (*sle)[sfMPTAmount] += delta; - view.update(sle); - } - else - { - // Decrease the Issuance OutstandingAmount - auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); - auto const redeem = netAmount.mpt().value(); - - // Underflow check for subtraction - if (!canSubtract(STAmount(mptIssue, outstanding), STAmount(mptIssue, redeem))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " - << mptIssue.getMptID() << ": " << outstanding << " < " << redeem; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem); - view.update(sleIssuance); - } - - if (issuer == sender) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: sender is the issuer, " - "cannot unlock MPTs."; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - // Decrease the MPT Holder EscrowedAmount - auto const mptokenID = keylet::mptoken(mptID.key, sender); - auto sle = view.peek(mptokenID); - if (!sle) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << sender; - return tecOBJECT_NOT_FOUND; - } // LCOV_EXCL_STOP - - if (!sle->isFieldPresent(sfLockedAmount)) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in MPToken for " - << to_string(sender); - return tecINTERNAL; - } // LCOV_EXCL_STOP - - auto const locked = sle->getFieldU64(sfLockedAmount); - auto const delta = grossAmount.mpt().value(); - - // Underflow check for subtraction - if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, delta))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " - << to_string(sender) << ": " << locked << " < " << delta; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - auto const newLocked = locked - delta; - if (newLocked == 0) - { - sle->makeFieldAbsent(sfLockedAmount); - } - else - { - sle->setFieldU64(sfLockedAmount, newLocked); - } - view.update(sle); - - // Note: The gross amount is the amount that was locked, the net - // amount is the amount that is being unlocked. The difference is the fee - // that was charged for the transfer. If this difference is greater than - // zero, we need to update the outstanding amount. - auto const diff = grossAmount.mpt().value() - netAmount.mpt().value(); - if (diff != 0) - { - auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); - // Underflow check for subtraction - if (!canSubtract(STAmount(mptIssue, outstanding), STAmount(mptIssue, diff))) - { // LCOV_EXCL_START - JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " - << mptIssue.getMptID() << ": " << outstanding << " < " << diff; - return tecINTERNAL; - } // LCOV_EXCL_STOP - - sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - diff); - view.update(sleIssuance); - } - return tesSUCCESS; -} - bool after(NetClock::time_point now, std::uint32_t mark) { diff --git a/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp new file mode 100644 index 0000000000..399494bc5f --- /dev/null +++ b/src/libxrpl/ledger/helpers/AccountRootHelpers.cpp @@ -0,0 +1,247 @@ +#include +// +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl { + +bool +isGlobalFrozen(ReadView const& view, AccountID const& issuer) +{ + if (isXRP(issuer)) + return false; + if (auto const sle = view.read(keylet::account(issuer))) + return sle->isFlag(lsfGlobalFreeze); + return false; +} + +// 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 +confineOwnerCount( + std::uint32_t current, + std::int32_t adjustment, + std::optional const& id = std::nullopt, + beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) +{ + std::uint32_t adjusted{current + adjustment}; + if (adjustment > 0) + { + // Overflow is well defined on unsigned + if (adjusted < current) + { + if (id) + { + JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!"; + } + adjusted = std::numeric_limits::max(); + } + } + else + { + // Underflow is well defined on unsigned + if (adjusted > current) + { + if (id) + { + JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!"; + } + adjusted = 0; + XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set"); + } + } + return adjusted; +} + +XRPAmount +xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j) +{ + auto const sle = view.read(keylet::account(id)); + if (sle == nullptr) + return beast::zero; + + // Return balance minus reserve + std::uint32_t const ownerCount = + confineOwnerCount(view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj); + + // Pseudo-accounts have no reserve requirement + auto const reserve = + isPseudoAccount(sle) ? XRPAmount{0} : view.fees().accountReserve(ownerCount); + + auto const fullBalance = sle->getFieldAmount(sfBalance); + + auto const balance = view.balanceHook(id, xrpAccount(), fullBalance); + + STAmount const amount = (balance < reserve) ? STAmount{0} : balance - reserve; + + JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id) + << " amount=" << amount.getFullText() + << " fullBalance=" << fullBalance.getFullText() + << " balance=" << balance.getFullText() << " reserve=" << reserve + << " ownerCount=" << ownerCount << " ownerCountAdj=" << ownerCountAdj; + + return amount.xrp(); +} + +Rate +transferRate(ReadView const& view, AccountID const& issuer) +{ + auto const sle = view.read(keylet::account(issuer)); + + if (sle && sle->isFieldPresent(sfTransferRate)) + return Rate{sle->getFieldU32(sfTransferRate)}; + + return parityRate; +} + +void +adjustOwnerCount( + ApplyView& view, + std::shared_ptr const& sle, + std::int32_t amount, + 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); +} + +AccountID +pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey) +{ + // This number must not be changed without an amendment + constexpr std::uint16_t maxAccountAttempts = 256; + for (std::uint16_t i = 0; i < maxAccountAttempts; ++i) + { + ripesha_hasher rsh; + auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey); + rsh(hash.data(), hash.size()); + AccountID const ret{static_cast(rsh)}; + if (!view.read(keylet::account(ret))) + return ret; + } + return beast::zero; +} + +// Pseudo-account designator fields MUST be maintained by including the +// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to +// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated, +// since a non-active amendment will not set any field, by definition. +// Specific properties of a pseudo-account are NOT checked here, that's what +// InvariantCheck is for. +[[nodiscard]] std::vector const& +getPseudoAccountFields() +{ + static std::vector const pseudoFields = []() { + auto const ar = LedgerFormats::getInstance().findByType(ltACCOUNT_ROOT); + if (!ar) + { + // LCOV_EXCL_START + LogicError( + "xrpl::getPseudoAccountFields : unable to find account root " + "ledger format"); + // LCOV_EXCL_STOP + } + auto const& soTemplate = ar->getSOTemplate(); + + std::vector pseudoFields; + for (auto const& field : soTemplate) + { + if (field.sField().shouldMeta(SField::sMD_PseudoAccount)) + pseudoFields.emplace_back(&field.sField()); + } + return pseudoFields; + }(); + return pseudoFields; +} + +[[nodiscard]] bool +isPseudoAccount( + std::shared_ptr sleAcct, + std::set const& pseudoFieldFilter) +{ + auto const& fields = getPseudoAccountFields(); + + // Intentionally use defensive coding here because it's cheap and makes the + // semantics of true return value clean. + return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT && + std::count_if( + fields.begin(), fields.end(), [&sleAcct, &pseudoFieldFilter](SField const* sf) -> bool { + return sleAcct->isFieldPresent(*sf) && + (pseudoFieldFilter.empty() || pseudoFieldFilter.contains(sf)); + }) > 0; +} + +Expected, TER> +createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField) +{ + [[maybe_unused]] + auto const& fields = getPseudoAccountFields(); + XRPL_ASSERT( + std::count_if( + fields.begin(), + fields.end(), + [&ownerField](SField const* sf) -> bool { return *sf == ownerField; }) == 1, + "xrpl::createPseudoAccount : valid owner field"); + + auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey); + if (accountId == beast::zero) + return Unexpected(tecDUPLICATE); + + // Create pseudo-account. + auto account = std::make_shared(keylet::account(accountId)); + account->setAccountID(sfAccount, accountId); + account->setFieldAmount(sfBalance, STAmount{}); + + // Pseudo-accounts can't submit transactions, so set the sequence number + // to 0 to make them easier to spot and verify, and add an extra level + // of protection. + std::uint32_t const seqno = // + view.rules().enabled(featureSingleAssetVault) || // + view.rules().enabled(featureLendingProtocol) // + ? 0 // + : view.seq(); + account->setFieldU32(sfSequence, seqno); + // Ignore reserves requirement, disable the master key, allow default + // rippling, and enable deposit authorization to prevent payments into + // pseudo-account. + account->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); + // Link the pseudo-account with its owner object. + account->setFieldH256(ownerField, pseudoOwnerKey); + + view.insert(account); + + return account; +} + +[[nodiscard]] TER +checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag) +{ + if (toSle == nullptr) + return tecNO_DST; + + // The tag is basically account-specific information we don't + // understand, but we can require someone to fill it in. + if (toSle->isFlag(lsfRequireDestTag) && !hasDestinationTag) + return tecDST_TAG_NEEDED; // Cannot send without a tag + + return tesSUCCESS; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/CredentialHelpers.cpp b/src/libxrpl/ledger/helpers/CredentialHelpers.cpp similarity index 99% rename from src/libxrpl/ledger/CredentialHelpers.cpp rename to src/libxrpl/ledger/helpers/CredentialHelpers.cpp index 0782eda67d..234ca7ea17 100644 --- a/src/libxrpl/ledger/CredentialHelpers.cpp +++ b/src/libxrpl/ledger/helpers/CredentialHelpers.cpp @@ -1,5 +1,7 @@ -#include +#include +// #include +#include #include #include diff --git a/src/libxrpl/ledger/helpers/DirectoryHelpers.cpp b/src/libxrpl/ledger/helpers/DirectoryHelpers.cpp new file mode 100644 index 0000000000..f0ca83f2cd --- /dev/null +++ b/src/libxrpl/ledger/helpers/DirectoryHelpers.cpp @@ -0,0 +1,177 @@ +#include +// +#include + +namespace xrpl { + +bool +dirFirst( + ApplyView& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry) +{ + return detail::internalDirFirst(view, root, page, index, entry); +} + +bool +dirNext( + ApplyView& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry) +{ + return detail::internalDirNext(view, root, page, index, entry); +} + +bool +cdirFirst( + ReadView const& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry) +{ + return detail::internalDirFirst(view, root, page, index, entry); +} + +bool +cdirNext( + ReadView const& view, + uint256 const& root, + std::shared_ptr& page, + unsigned int& index, + uint256& entry) +{ + return detail::internalDirNext(view, root, page, index, entry); +} + +void +forEachItem( + ReadView const& view, + Keylet const& root, + std::function const&)> const& f) +{ + XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::forEachItem : valid root type"); + + if (root.type != ltDIR_NODE) + return; + + auto pos = root; + + while (true) + { + auto sle = view.read(pos); + if (!sle) + return; + for (auto const& key : sle->getFieldV256(sfIndexes)) + f(view.read(keylet::child(key))); + auto const next = sle->getFieldU64(sfIndexNext); + if (!next) + return; + pos = keylet::page(root, next); + } +} + +bool +forEachItemAfter( + ReadView const& view, + Keylet const& root, + uint256 const& after, + std::uint64_t const hint, + unsigned int limit, + std::function const&)> const& f) +{ + XRPL_ASSERT(root.type == ltDIR_NODE, "xrpl::forEachItemAfter : valid root type"); + + if (root.type != ltDIR_NODE) + return false; + + auto currentIndex = root; + + // If startAfter is not zero try jumping to that page using the hint + if (after.isNonZero()) + { + auto const hintIndex = keylet::page(root, hint); + + if (auto hintDir = view.read(hintIndex)) + { + for (auto const& key : hintDir->getFieldV256(sfIndexes)) + { + if (key == after) + { + // We found the hint, we can start here + currentIndex = hintIndex; + break; + } + } + } + + bool found = false; + for (;;) + { + auto const ownerDir = view.read(currentIndex); + if (!ownerDir) + return found; + for (auto const& key : ownerDir->getFieldV256(sfIndexes)) + { + if (!found) + { + if (key == after) + found = true; + } + else if (f(view.read(keylet::child(key))) && limit-- <= 1) + { + return found; + } + } + + auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext); + if (uNodeNext == 0) + return found; + currentIndex = keylet::page(root, uNodeNext); + } + } + else + { + for (;;) + { + auto const ownerDir = view.read(currentIndex); + if (!ownerDir) + return true; + for (auto const& key : ownerDir->getFieldV256(sfIndexes)) + { + if (f(view.read(keylet::child(key))) && limit-- <= 1) + return true; + } + auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext); + if (uNodeNext == 0) + return true; + currentIndex = keylet::page(root, uNodeNext); + } + } +} + +bool +dirIsEmpty(ReadView const& view, Keylet const& k) +{ + auto const sleNode = view.read(k); + if (!sleNode) + return true; + if (!sleNode->getFieldV256(sfIndexes).empty()) + return false; + // The first page of a directory may legitimately be empty even if there + // are other pages (the first page is the anchor page) so check to see if + // there is another page. If there is, the directory isn't empty. + return sleNode->getFieldU64(sfIndexNext) == 0; +} + +std::function +describeOwnerDir(AccountID const& account) +{ + return [account](std::shared_ptr const& sle) { (*sle)[sfOwner] = account; }; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp new file mode 100644 index 0000000000..cbf37a06a8 --- /dev/null +++ b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp @@ -0,0 +1,766 @@ +#include +// +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xrpl { + +// Forward declarations for functions that remain in View.h/cpp +bool +isVaultPseudoAccountFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptShare, + int depth); + +[[nodiscard]] TER +dirLink( + ApplyView& view, + AccountID const& owner, + std::shared_ptr& object, + SF_UINT64 const& node = sfOwnerNode); + +bool +isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue) +{ + if (auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID()))) + return sle->isFlag(lsfMPTLocked); + return false; +} + +bool +isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) +{ + if (auto const sle = view.read(keylet::mptoken(mptIssue.getMptID(), account))) + return sle->isFlag(lsfMPTLocked); + return false; +} + +bool +isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth) +{ + return isGlobalFrozen(view, mptIssue) || isIndividualFrozen(view, account, mptIssue) || + isVaultPseudoAccountFrozen(view, account, mptIssue, depth); +} + +[[nodiscard]] bool +isAnyFrozen( + ReadView const& view, + std::initializer_list const& accounts, + MPTIssue const& mptIssue, + int depth) +{ + if (isGlobalFrozen(view, mptIssue)) + return true; + + for (auto const& account : accounts) + { + if (isIndividualFrozen(view, account, mptIssue)) + return true; + } + + for (auto const& account : accounts) + { + if (isVaultPseudoAccountFrozen(view, account, mptIssue, depth)) + return true; + } + + return false; +} + +Rate +transferRate(ReadView const& view, MPTID const& issuanceID) +{ + // fee is 0-50,000 (0-50%), rate is 1,000,000,000-2,000,000,000 + // For example, if transfer fee is 50% then 10,000 * 50,000 = 500,000 + // which represents 50% of 1,000,000,000 + if (auto const sle = view.read(keylet::mptIssuance(issuanceID)); + sle && sle->isFieldPresent(sfTransferFee)) + return Rate{1'000'000'000u + 10'000 * sle->getFieldU16(sfTransferFee)}; + + return parityRate; +} + +[[nodiscard]] TER +canAddHolding(ReadView const& view, MPTIssue const& mptIssue) +{ + auto mptID = mptIssue.getMptID(); + auto issuance = view.read(keylet::mptIssuance(mptID)); + if (!issuance) + { + return tecOBJECT_NOT_FOUND; + } + if (!issuance->isFlag(lsfMPTCanTransfer)) + { + return tecNO_AUTH; + } + + return tesSUCCESS; +} + +[[nodiscard]] TER +addEmptyHolding( + ApplyView& view, + AccountID const& accountID, + XRPAmount priorBalance, + MPTIssue const& mptIssue, + beast::Journal journal) +{ + auto const& mptID = mptIssue.getMptID(); + auto const mpt = view.peek(keylet::mptIssuance(mptID)); + if (!mpt) + return tefINTERNAL; // LCOV_EXCL_LINE + if (mpt->isFlag(lsfMPTLocked)) + return tefINTERNAL; // LCOV_EXCL_LINE + if (view.peek(keylet::mptoken(mptID, accountID))) + return tecDUPLICATE; + if (accountID == mptIssue.getIssuer()) + return tesSUCCESS; + + return authorizeMPToken(view, priorBalance, mptID, accountID, journal); +} + +[[nodiscard]] TER +authorizeMPToken( + ApplyView& view, + XRPAmount const& priorBalance, + MPTID const& mptIssuanceID, + AccountID const& account, + beast::Journal journal, + std::uint32_t flags, + std::optional holderID) +{ + auto const sleAcct = view.peek(keylet::account(account)); + if (!sleAcct) + return tecINTERNAL; // LCOV_EXCL_LINE + + // If the account that submitted the tx is a holder + // Note: `account_` is holder's account + // `holderID` is NOT used + if (!holderID) + { + // When a holder wants to unauthorize/delete a MPT, the ledger must + // - delete mptokenKey from owner directory + // - delete the MPToken + if (flags & tfMPTUnauthorize) + { + auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); + auto const sleMpt = view.peek(mptokenKey); + if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (!view.dirRemove( + keylet::ownerDir(account), (*sleMpt)[sfOwnerNode], sleMpt->key(), false)) + return tecINTERNAL; // LCOV_EXCL_LINE + + adjustOwnerCount(view, sleAcct, -1, journal); + + view.erase(sleMpt); + return tesSUCCESS; + } + + // A potential holder wants to authorize/hold a mpt, the ledger must: + // - add the new mptokenKey to the owner directory + // - create the MPToken object for the holder + + // 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::zero) + : view.fees().accountReserve(uOwnerCount + 1)); + + if (priorBalance < reserveCreate) + return tecINSUFFICIENT_RESERVE; + + // Defensive check before we attempt to create MPToken for the issuer + auto const mpt = view.read(keylet::mptIssuance(mptIssuanceID)); + if (!mpt || mpt->getAccountID(sfIssuer) == account) + { + // LCOV_EXCL_START + UNREACHABLE("xrpl::authorizeMPToken : invalid issuance or issuers token"); + if (view.rules().enabled(featureLendingProtocol)) + return tecINTERNAL; + // LCOV_EXCL_STOP + } + + auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); + auto mptoken = std::make_shared(mptokenKey); + if (auto ter = dirLink(view, account, mptoken)) + return ter; // LCOV_EXCL_LINE + + (*mptoken)[sfAccount] = account; + (*mptoken)[sfMPTokenIssuanceID] = mptIssuanceID; + (*mptoken)[sfFlags] = 0; + view.insert(mptoken); + + // Update owner count. + adjustOwnerCount(view, sleAcct, 1, journal); + + return tesSUCCESS; + } + + auto const sleMptIssuance = view.read(keylet::mptIssuance(mptIssuanceID)); + if (!sleMptIssuance) + return tecINTERNAL; // LCOV_EXCL_LINE + + // If the account that submitted this tx is the issuer of the MPT + // Note: `account_` is issuer's account + // `holderID` is holder's account + if (account != (*sleMptIssuance)[sfIssuer]) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const sleMpt = view.peek(keylet::mptoken(mptIssuanceID, *holderID)); + if (!sleMpt) + return tecINTERNAL; // LCOV_EXCL_LINE + + std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags); + std::uint32_t flagsOut = flagsIn; + + // Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on + // their MPToken + if (flags & tfMPTUnauthorize) + { + flagsOut &= ~lsfMPTAuthorized; + } + // Issuer wants to authorize a holder, set lsfMPTAuthorized on their + // MPToken + else + { + flagsOut |= lsfMPTAuthorized; + } + + if (flagsIn != flagsOut) + sleMpt->setFieldU32(sfFlags, flagsOut); + + view.update(sleMpt); + return tesSUCCESS; +} + +[[nodiscard]] TER +removeEmptyHolding( + ApplyView& view, + AccountID const& accountID, + MPTIssue const& mptIssue, + beast::Journal journal) +{ + // If the account is the issuer, then no token should exist. MPTs do not + // have the legacy ability to create such a situation, but check anyway. If + // 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)); + 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 + // balance, it can not just be deleted, because that will throw the issuance + // 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) + return tecHAS_OBLIGATIONS; + + return authorizeMPToken( + view, + {}, // priorBalance + mptID, + accountID, + journal, + tfMPTUnauthorize // flags + ); +} + +[[nodiscard]] TER +requireAuth( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& account, + AuthType authType, + int depth) +{ + auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); + auto const sleIssuance = view.read(mptID); + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + + auto const mptIssuer = sleIssuance->getAccountID(sfIssuer); + + // issuer is always "authorized" + if (mptIssuer == account) // Issuer won't have MPToken + return tesSUCCESS; + + bool const featureSAVEnabled = view.rules().enabled(featureSingleAssetVault); + + if (featureSAVEnabled) + { + if (depth >= maxAssetCheckDepth) + return tecINTERNAL; // LCOV_EXCL_LINE + + // requireAuth is recursive if the issuer is a vault pseudo-account + auto const sleIssuer = view.read(keylet::account(mptIssuer)); + if (!sleIssuer) + return tefINTERNAL; // LCOV_EXCL_LINE + + if (sleIssuer->isFieldPresent(sfVaultID)) + { + auto const sleVault = view.read(keylet::vault(sleIssuer->getFieldH256(sfVaultID))); + if (!sleVault) + return tefINTERNAL; // LCOV_EXCL_LINE + + auto const asset = sleVault->at(sfAsset); + if (auto const err = std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return requireAuth(view, issue, account, authType); + } + else + { + return requireAuth(view, issue, account, authType, depth + 1); + } + }, + asset.value()); + !isTesSuccess(err)) + return err; + } + } + + auto const mptokenID = keylet::mptoken(mptID.key, account); + auto const sleToken = view.read(mptokenID); + + // if account has no MPToken, fail + if (!sleToken && (authType == AuthType::StrongAuth || authType == AuthType::Legacy)) + return tecNO_AUTH; + + // Note, this check is not amendment-gated because DomainID will be always + // empty **unless** writing to it has been enabled by an amendment + auto const maybeDomainID = sleIssuance->at(~sfDomainID); + if (maybeDomainID) + { + XRPL_ASSERT( + sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth, + "xrpl::requireAuth : issuance requires authorization"); + // ter = tefINTERNAL | tecOBJECT_NOT_FOUND | tecNO_AUTH | tecEXPIRED + auto const ter = credentials::validDomain(view, *maybeDomainID, account); + if (isTesSuccess(ter)) + { + return ter; // Note: sleToken might be null + } + if (!sleToken) + { + return ter; + } + // We ignore error from validDomain if we found sleToken, as it could + // belong to someone who is explicitly authorized e.g. a vault owner. + } + + if (featureSAVEnabled) + { + // Implicitly authorize Vault and LoanBroker pseudo-accounts + if (isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID})) + return tesSUCCESS; + } + + // mptoken must be authorized if issuance enabled requireAuth + if (sleIssuance->isFlag(lsfMPTRequireAuth) && + (!sleToken || !sleToken->isFlag(lsfMPTAuthorized))) + return tecNO_AUTH; + + return tesSUCCESS; // Note: sleToken might be null +} + +[[nodiscard]] TER +enforceMPTokenAuthorization( + ApplyView& view, + MPTID const& mptIssuanceID, + AccountID const& account, + XRPAmount const& priorBalance, // for MPToken authorization + beast::Journal j) +{ + auto const sleIssuance = view.read(keylet::mptIssuance(mptIssuanceID)); + if (!sleIssuance) + return tefINTERNAL; // LCOV_EXCL_LINE + + XRPL_ASSERT( + sleIssuance->isFlag(lsfMPTRequireAuth), + "xrpl::enforceMPTokenAuthorization : authorization required"); + + if (account == sleIssuance->at(sfIssuer)) + return tefINTERNAL; // LCOV_EXCL_LINE + + auto const keylet = keylet::mptoken(mptIssuanceID, account); + auto const sleToken = view.read(keylet); // NOTE: might be null + auto const maybeDomainID = sleIssuance->at(~sfDomainID); + bool expired = false; + bool const authorizedByDomain = [&]() -> bool { + // NOTE: defensive here, should be checked in preclaim + if (!maybeDomainID.has_value()) + return false; // LCOV_EXCL_LINE + + auto const ter = verifyValidDomain(view, account, *maybeDomainID, j); + if (isTesSuccess(ter)) + return true; + if (ter == tecEXPIRED) + expired = true; + return false; + }(); + + if (!authorizedByDomain && sleToken == nullptr) + { + // Could not find MPToken and won't create one, could be either of: + // + // 1. Field sfDomainID not set in MPTokenIssuance or + // 2. Account has no matching and accepted credentials or + // 3. Account has all expired credentials (deleted in verifyValidDomain) + // + // Either way, return tecNO_AUTH and there is nothing else to do + return expired ? tecEXPIRED : tecNO_AUTH; + } + if (!authorizedByDomain && maybeDomainID.has_value()) + { + // Found an MPToken but the account is not authorized and we expect + // it to have been authorized by the domain. This could be because the + // credentials used to create the MPToken have expired or been deleted. + return expired ? tecEXPIRED : tecNO_AUTH; + } + if (!authorizedByDomain) + { + // We found an MPToken, but sfDomainID is not set, so this is a classic + // MPToken which requires authorization by the token issuer. + XRPL_ASSERT( + sleToken != nullptr && !maybeDomainID.has_value(), + "xrpl::enforceMPTokenAuthorization : found MPToken"); + if (sleToken->isFlag(lsfMPTAuthorized)) + return tesSUCCESS; + + return tecNO_AUTH; + } + if (authorizedByDomain && sleToken != nullptr) + { + // Found an MPToken, authorized by the domain. Ignore authorization flag + // lsfMPTAuthorized because it is meaningless. Return tesSUCCESS + XRPL_ASSERT( + maybeDomainID.has_value(), + "xrpl::enforceMPTokenAuthorization : found MPToken for domain"); + return tesSUCCESS; + } + if (authorizedByDomain) + { + // Could not find MPToken but there should be one because we are + // authorized by domain. Proceed to create it, then return tesSUCCESS + XRPL_ASSERT( + maybeDomainID.has_value() && sleToken == nullptr, + "xrpl::enforceMPTokenAuthorization : new MPToken for domain"); + if (auto const err = authorizeMPToken( + view, + priorBalance, // priorBalance + mptIssuanceID, // mptIssuanceID + account, // account + j); + !isTesSuccess(err)) + return err; + + return tesSUCCESS; + } + + // LCOV_EXCL_START + UNREACHABLE("xrpl::enforceMPTokenAuthorization : condition list is incomplete"); + return tefINTERNAL; + // LCOV_EXCL_STOP +} + +TER +canTransfer( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& from, + AccountID const& to) +{ + auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); + auto const sleIssuance = view.read(mptID); + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + + if (!(sleIssuance->getFieldU32(sfFlags) & lsfMPTCanTransfer)) + { + if (from != (*sleIssuance)[sfIssuer] && to != (*sleIssuance)[sfIssuer]) + return TER{tecNO_AUTH}; + } + return tesSUCCESS; +} + +TER +rippleLockEscrowMPT( + ApplyView& view, + AccountID const& sender, + STAmount const& amount, + beast::Journal j) +{ + auto const mptIssue = amount.get(); + auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); + auto sleIssuance = view.peek(mptID); + if (!sleIssuance) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleLockEscrowMPT: MPT issuance not found for " + << mptIssue.getMptID(); + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP + + if (amount.getIssuer() == sender) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleLockEscrowMPT: sender is the issuer, cannot lock MPTs."; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + // 1. Decrease the MPT Holder MPTAmount + // 2. Increase the MPT Holder EscrowedAmount + { + auto const mptokenID = keylet::mptoken(mptID.key, sender); + auto sle = view.peek(mptokenID); + if (!sle) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleLockEscrowMPT: MPToken not found for " << sender; + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP + + auto const amt = sle->getFieldU64(sfMPTAmount); + auto const pay = amount.mpt().value(); + + // Underflow check for subtraction + if (!canSubtract(STAmount(mptIssue, amt), STAmount(mptIssue, pay))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleLockEscrowMPT: insufficient MPTAmount for " + << to_string(sender) << ": " << amt << " < " << pay; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + (*sle)[sfMPTAmount] = amt - pay; + + // Overflow check for addition + uint64_t const locked = (*sle)[~sfLockedAmount].value_or(0); + + if (!canAdd(STAmount(mptIssue, locked), STAmount(mptIssue, pay))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleLockEscrowMPT: overflow on locked amount for " + << to_string(sender) << ": " << locked << " + " << pay; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + if (sle->isFieldPresent(sfLockedAmount)) + { + (*sle)[sfLockedAmount] += pay; + } + else + { + sle->setFieldU64(sfLockedAmount, pay); + } + + view.update(sle); + } + + // 1. Increase the Issuance EscrowedAmount + // 2. DO NOT change the Issuance OutstandingAmount + { + uint64_t const issuanceEscrowed = (*sleIssuance)[~sfLockedAmount].value_or(0); + auto const pay = amount.mpt().value(); + + // Overflow check for addition + if (!canAdd(STAmount(mptIssue, issuanceEscrowed), STAmount(mptIssue, pay))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleLockEscrowMPT: overflow on issuance " + "locked amount for " + << mptIssue.getMptID() << ": " << issuanceEscrowed << " + " << pay; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + if (sleIssuance->isFieldPresent(sfLockedAmount)) + { + (*sleIssuance)[sfLockedAmount] += pay; + } + else + { + sleIssuance->setFieldU64(sfLockedAmount, pay); + } + + view.update(sleIssuance); + } + return tesSUCCESS; +} + +TER +rippleUnlockEscrowMPT( + ApplyView& view, + AccountID const& sender, + AccountID const& receiver, + STAmount const& netAmount, + STAmount const& grossAmount, + beast::Journal j) +{ + if (!view.rules().enabled(fixTokenEscrowV1)) + { + XRPL_ASSERT( + netAmount == grossAmount, "xrpl::rippleUnlockEscrowMPT : netAmount == grossAmount"); + } + + auto const& issuer = netAmount.getIssuer(); + auto const& mptIssue = netAmount.get(); + auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); + auto sleIssuance = view.peek(mptID); + if (!sleIssuance) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: MPT issuance not found for " + << mptIssue.getMptID(); + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP + + // Decrease the Issuance EscrowedAmount + { + if (!sleIssuance->isFieldPresent(sfLockedAmount)) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in issuance for " + << mptIssue.getMptID(); + return tecINTERNAL; + } // LCOV_EXCL_STOP + + auto const locked = sleIssuance->getFieldU64(sfLockedAmount); + auto const redeem = grossAmount.mpt().value(); + + // Underflow check for subtraction + if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, redeem))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " + << mptIssue.getMptID() << ": " << locked << " < " << redeem; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + auto const newLocked = locked - redeem; + if (newLocked == 0) + { + sleIssuance->makeFieldAbsent(sfLockedAmount); + } + else + { + sleIssuance->setFieldU64(sfLockedAmount, newLocked); + } + view.update(sleIssuance); + } + + if (issuer != receiver) + { + // Increase the MPT Holder MPTAmount + auto const mptokenID = keylet::mptoken(mptID.key, receiver); + auto sle = view.peek(mptokenID); + if (!sle) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << receiver; + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP + + auto current = sle->getFieldU64(sfMPTAmount); + auto delta = netAmount.mpt().value(); + + // Overflow check for addition + if (!canAdd(STAmount(mptIssue, current), STAmount(mptIssue, delta))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: overflow on MPTAmount for " + << to_string(receiver) << ": " << current << " + " << delta; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + (*sle)[sfMPTAmount] += delta; + view.update(sle); + } + else + { + // Decrease the Issuance OutstandingAmount + auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); + auto const redeem = netAmount.mpt().value(); + + // Underflow check for subtraction + if (!canSubtract(STAmount(mptIssue, outstanding), STAmount(mptIssue, redeem))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " + << mptIssue.getMptID() << ": " << outstanding << " < " << redeem; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem); + view.update(sleIssuance); + } + + if (issuer == sender) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: sender is the issuer, " + "cannot unlock MPTs."; + return tecINTERNAL; + } // LCOV_EXCL_STOP + // Decrease the MPT Holder EscrowedAmount + auto const mptokenID = keylet::mptoken(mptID.key, sender); + auto sle = view.peek(mptokenID); + if (!sle) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: MPToken not found for " << sender; + return tecOBJECT_NOT_FOUND; + } // LCOV_EXCL_STOP + + if (!sle->isFieldPresent(sfLockedAmount)) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: no locked amount in MPToken for " + << to_string(sender); + return tecINTERNAL; + } // LCOV_EXCL_STOP + + auto const locked = sle->getFieldU64(sfLockedAmount); + auto const delta = grossAmount.mpt().value(); + + // Underflow check for subtraction + if (!canSubtract(STAmount(mptIssue, locked), STAmount(mptIssue, delta))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient locked amount for " + << to_string(sender) << ": " << locked << " < " << delta; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + auto const newLocked = locked - delta; + if (newLocked == 0) + { + sle->makeFieldAbsent(sfLockedAmount); + } + else + { + sle->setFieldU64(sfLockedAmount, newLocked); + } + view.update(sle); + + // Note: The gross amount is the amount that was locked, the net + // amount is the amount that is being unlocked. The difference is the fee + // that was charged for the transfer. If this difference is greater than + // zero, we need to update the outstanding amount. + auto const diff = grossAmount.mpt().value() - netAmount.mpt().value(); + if (diff != 0) + { + auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); + // Underflow check for subtraction + if (!canSubtract(STAmount(mptIssue, outstanding), STAmount(mptIssue, diff))) + { // LCOV_EXCL_START + JLOG(j.error()) << "rippleUnlockEscrowMPT: insufficient outstanding amount for " + << mptIssue.getMptID() << ": " << outstanding << " < " << diff; + return tecINTERNAL; + } // LCOV_EXCL_STOP + + sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - diff); + view.update(sleIssuance); + } + return tesSUCCESS; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/helpers/OfferHelpers.cpp b/src/libxrpl/ledger/helpers/OfferHelpers.cpp new file mode 100644 index 0000000000..9422153b10 --- /dev/null +++ b/src/libxrpl/ledger/helpers/OfferHelpers.cpp @@ -0,0 +1,58 @@ +#include +// +#include +#include +#include +#include + +namespace xrpl { + +TER +offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j) +{ + if (!sle) + return tesSUCCESS; + auto offerIndex = sle->key(); + auto owner = sle->getAccountID(sfAccount); + + // Detect legacy directories. + uint256 uDirectory = sle->getFieldH256(sfBookDirectory); + + if (!view.dirRemove(keylet::ownerDir(owner), sle->getFieldU64(sfOwnerNode), offerIndex, false)) + { + return tefBAD_LEDGER; // LCOV_EXCL_LINE + } + + if (!view.dirRemove(keylet::page(uDirectory), sle->getFieldU64(sfBookNode), offerIndex, false)) + { + return tefBAD_LEDGER; // LCOV_EXCL_LINE + } + + if (sle->isFieldPresent(sfAdditionalBooks)) + { + XRPL_ASSERT( + sle->isFlag(lsfHybrid) && sle->isFieldPresent(sfDomainID), + "xrpl::offerDelete : should be a hybrid domain offer"); + + auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks); + + for (auto const& bookDir : additionalBookDirs) + { + auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory); + auto const& dirNode = bookDir.getFieldU64(sfBookNode); + + if (!view.dirRemove(keylet::page(dirIndex), dirNode, offerIndex, false)) + { + return tefBAD_LEDGER; // LCOV_EXCL_LINE + } + } + } + + adjustOwnerCount(view, view.peek(keylet::account(owner)), -1, j); + + view.erase(sle); + + return tesSUCCESS; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/helpers/RippleStateHelpers.cpp b/src/libxrpl/ledger/helpers/RippleStateHelpers.cpp new file mode 100644 index 0000000000..e88afe0cfb --- /dev/null +++ b/src/libxrpl/ledger/helpers/RippleStateHelpers.cpp @@ -0,0 +1,759 @@ +#include +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xrpl { + +//------------------------------------------------------------------------------ +// +// Credit functions (from Credit.cpp) +// +//------------------------------------------------------------------------------ + +STAmount +creditLimit( + ReadView const& view, + AccountID const& account, + AccountID const& issuer, + Currency const& currency) +{ + STAmount result(Issue{currency, account}); + + auto sleRippleState = view.read(keylet::line(account, issuer, currency)); + + if (sleRippleState) + { + result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit); + result.setIssuer(account); + } + + XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditLimit : result issuer match"); + XRPL_ASSERT(result.getCurrency() == currency, "xrpl::creditLimit : result currency match"); + return result; +} + +IOUAmount +creditLimit2(ReadView const& v, AccountID const& acc, AccountID const& iss, Currency const& cur) +{ + return toAmount(creditLimit(v, acc, iss, cur)); +} + +STAmount +creditBalance( + ReadView const& view, + AccountID const& account, + AccountID const& issuer, + Currency const& currency) +{ + STAmount result(Issue{currency, account}); + + auto sleRippleState = view.read(keylet::line(account, issuer, currency)); + + if (sleRippleState) + { + result = sleRippleState->getFieldAmount(sfBalance); + if (account < issuer) + result.negate(); + result.setIssuer(account); + } + + XRPL_ASSERT(result.getIssuer() == account, "xrpl::creditBalance : result issuer match"); + XRPL_ASSERT(result.getCurrency() == currency, "xrpl::creditBalance : result currency match"); + return result; +} + +//------------------------------------------------------------------------------ +// +// Freeze checking (IOU-specific) +// +//------------------------------------------------------------------------------ + +bool +isIndividualFrozen( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer) +{ + if (isXRP(currency)) + return false; + if (issuer != account) + { + // Check if the issuer froze the line + auto const sle = view.read(keylet::line(account, issuer, currency)); + if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) + return true; + } + return false; +} + +// Can the specified account spend the specified currency issued by +// the specified issuer or does the freeze flag prohibit it? +bool +isFrozen( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer) +{ + if (isXRP(currency)) + return false; + auto sle = view.read(keylet::account(issuer)); + if (sle && sle->isFlag(lsfGlobalFreeze)) + return true; + if (issuer != account) + { + // Check if the issuer froze the line + sle = view.read(keylet::line(account, issuer, currency)); + if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze)) + return true; + } + return false; +} + +bool +isDeepFrozen( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer) +{ + if (isXRP(currency)) + { + return false; + } + + if (issuer == account) + { + return false; + } + + auto const sle = view.read(keylet::line(account, issuer, currency)); + if (!sle) + { + return false; + } + + return sle->isFlag(lsfHighDeepFreeze) || sle->isFlag(lsfLowDeepFreeze); +} + +//------------------------------------------------------------------------------ +// +// Trust line operations +// +//------------------------------------------------------------------------------ + +TER +trustCreate( + ApplyView& view, + bool const bSrcHigh, + AccountID const& uSrcAccountID, + AccountID const& uDstAccountID, + uint256 const& uIndex, // --> ripple state entry + SLE::ref sleAccount, // --> the account being set. + bool const bAuth, // --> authorize account. + bool const bNoRipple, // --> others cannot ripple through + bool const bFreeze, // --> funds cannot leave + bool bDeepFreeze, // --> can neither receive nor send funds + STAmount const& saBalance, // --> balance of account being set. + // Issuer should be noAccount() + STAmount const& saLimit, // --> limit for account being set. + // Issuer should be the account being set. + std::uint32_t uQualityIn, + std::uint32_t uQualityOut, + beast::Journal j) +{ + JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", " + << to_string(uDstAccountID) << ", " << saBalance.getFullText(); + + auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID; + auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID; + if (uLowAccountID == uHighAccountID) + { + // LCOV_EXCL_START + UNREACHABLE("xrpl::trustCreate : trust line to self"); + if (view.rules().enabled(featureLendingProtocol)) + return tecINTERNAL; + // LCOV_EXCL_STOP + } + + auto const sleRippleState = std::make_shared(ltRIPPLE_STATE, uIndex); + view.insert(sleRippleState); + + auto lowNode = view.dirInsert( + keylet::ownerDir(uLowAccountID), sleRippleState->key(), describeOwnerDir(uLowAccountID)); + + if (!lowNode) + return tecDIR_FULL; // LCOV_EXCL_LINE + + auto highNode = view.dirInsert( + keylet::ownerDir(uHighAccountID), sleRippleState->key(), describeOwnerDir(uHighAccountID)); + + if (!highNode) + return tecDIR_FULL; // LCOV_EXCL_LINE + + bool const bSetDst = saLimit.getIssuer() == uDstAccountID; + bool const bSetHigh = bSrcHigh ^ bSetDst; + + XRPL_ASSERT(sleAccount, "xrpl::trustCreate : non-null SLE"); + if (!sleAccount) + return tefINTERNAL; // LCOV_EXCL_LINE + + XRPL_ASSERT( + sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID), + "xrpl::trustCreate : matching account ID"); + auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID)); + if (!slePeer) + return tecNO_TARGET; + + // Remember deletion hints. + sleRippleState->setFieldU64(sfLowNode, *lowNode); + sleRippleState->setFieldU64(sfHighNode, *highNode); + + sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit); + sleRippleState->setFieldAmount( + bSetHigh ? sfLowLimit : sfHighLimit, + STAmount(Issue{saBalance.getCurrency(), bSetDst ? uSrcAccountID : uDstAccountID})); + + if (uQualityIn) + sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn); + + if (uQualityOut) + sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut); + + std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve; + + if (bAuth) + { + uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth); + } + if (bNoRipple) + { + uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple); + } + if (bFreeze) + { + uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze); + } + if (bDeepFreeze) + { + uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze); + } + + if ((slePeer->getFlags() & lsfDefaultRipple) == 0) + { + // The other side's default is no rippling + uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple); + } + + sleRippleState->setFieldU32(sfFlags, uFlags); + adjustOwnerCount(view, sleAccount, 1, j); + + // ONLY: Create ripple balance. + sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance); + + view.creditHook(uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed()); + + return tesSUCCESS; +} + +TER +trustDelete( + ApplyView& view, + std::shared_ptr const& sleRippleState, + AccountID const& uLowAccountID, + AccountID const& uHighAccountID, + beast::Journal j) +{ + // Detect legacy dirs. + std::uint64_t uLowNode = sleRippleState->getFieldU64(sfLowNode); + std::uint64_t uHighNode = sleRippleState->getFieldU64(sfHighNode); + + JLOG(j.trace()) << "trustDelete: Deleting ripple line: low"; + + if (!view.dirRemove(keylet::ownerDir(uLowAccountID), uLowNode, sleRippleState->key(), false)) + { + return tefBAD_LEDGER; // LCOV_EXCL_LINE + } + + JLOG(j.trace()) << "trustDelete: Deleting ripple line: high"; + + if (!view.dirRemove(keylet::ownerDir(uHighAccountID), uHighNode, sleRippleState->key(), false)) + { + return tefBAD_LEDGER; // LCOV_EXCL_LINE + } + + JLOG(j.trace()) << "trustDelete: Deleting ripple line: state"; + view.erase(sleRippleState); + + return tesSUCCESS; +} + +//------------------------------------------------------------------------------ +// +// IOU issuance/redemption +// +//------------------------------------------------------------------------------ + +static bool +updateTrustLine( + ApplyView& view, + SLE::pointer state, + bool bSenderHigh, + AccountID const& sender, + STAmount const& before, + STAmount const& after, + beast::Journal j) +{ + if (!state) + return false; + std::uint32_t const flags(state->getFieldU32(sfFlags)); + + auto sle = view.peek(keylet::account(sender)); + if (!sle) + return false; + + // YYY Could skip this if rippling in reverse. + if (before > beast::zero + // Sender balance was positive. + && after <= beast::zero + // Sender is zero or negative. + && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) + // Sender reserve is set. + && static_cast(flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != + static_cast(sle->getFlags() & lsfDefaultRipple) && + !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && + !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) + // Sender trust limit is 0. + && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) + // Sender quality in is 0. + && !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) + // Sender quality out is 0. + { + // VFALCO Where is the line being deleted? + // Clear the reserve of the sender, possibly delete the line! + adjustOwnerCount(view, sle, -1, j); + + // Clear reserve flag. + state->setFieldU32(sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); + + // Balance is zero, receiver reserve is clear. + if (!after // Balance is zero. + && !(flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve))) + return true; + } + return false; +} + +TER +issueIOU( + ApplyView& view, + AccountID const& account, + STAmount const& amount, + Issue const& issue, + beast::Journal j) +{ + XRPL_ASSERT( + !isXRP(account) && !isXRP(issue.account), + "xrpl::issueIOU : neither account nor issuer is XRP"); + + // Consistency check + XRPL_ASSERT(issue == amount.issue(), "xrpl::issueIOU : matching issue"); + + // Can't send to self! + XRPL_ASSERT(issue.account != account, "xrpl::issueIOU : not issuer account"); + + JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": " << amount.getFullText(); + + bool bSenderHigh = issue.account > account; + + auto const index = keylet::line(issue.account, account, issue.currency); + + if (auto state = view.peek(index)) + { + STAmount final_balance = state->getFieldAmount(sfBalance); + + if (bSenderHigh) + final_balance.negate(); // Put balance in sender terms. + + STAmount const start_balance = final_balance; + + final_balance -= amount; + + auto const must_delete = updateTrustLine( + view, state, bSenderHigh, issue.account, start_balance, final_balance, j); + + view.creditHook(issue.account, account, amount, start_balance); + + if (bSenderHigh) + final_balance.negate(); + + // Adjust the balance on the trust line if necessary. We do this even + // if we are going to delete the line to reflect the correct balance + // at the time of deletion. + state->setFieldAmount(sfBalance, final_balance); + if (must_delete) + { + return trustDelete( + view, + state, + bSenderHigh ? account : issue.account, + bSenderHigh ? issue.account : account, + j); + } + + view.update(state); + + return tesSUCCESS; + } + + // NIKB TODO: The limit uses the receiver's account as the issuer and + // this is unnecessarily inefficient as copying which could be avoided + // is now required. Consider available options. + STAmount const limit(Issue{issue.currency, account}); + STAmount final_balance = amount; + + final_balance.setIssuer(noAccount()); + + auto const receiverAccount = view.peek(keylet::account(account)); + if (!receiverAccount) + return tefINTERNAL; // LCOV_EXCL_LINE + + bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0; + + return trustCreate( + view, + bSenderHigh, + issue.account, + account, + index.key, + receiverAccount, + false, + noRipple, + false, + false, + final_balance, + limit, + 0, + 0, + j); +} + +TER +redeemIOU( + ApplyView& view, + AccountID const& account, + STAmount const& amount, + Issue const& issue, + beast::Journal j) +{ + XRPL_ASSERT( + !isXRP(account) && !isXRP(issue.account), + "xrpl::redeemIOU : neither account nor issuer is XRP"); + + // Consistency check + XRPL_ASSERT(issue == amount.issue(), "xrpl::redeemIOU : matching issue"); + + // Can't send to self! + XRPL_ASSERT(issue.account != account, "xrpl::redeemIOU : not issuer account"); + + JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": " << amount.getFullText(); + + bool bSenderHigh = account > issue.account; + + if (auto state = view.peek(keylet::line(account, issue.account, issue.currency))) + { + STAmount final_balance = state->getFieldAmount(sfBalance); + + if (bSenderHigh) + final_balance.negate(); // Put balance in sender terms. + + STAmount const start_balance = final_balance; + + final_balance -= amount; + + auto const must_delete = + updateTrustLine(view, state, bSenderHigh, account, start_balance, final_balance, j); + + view.creditHook(account, issue.account, amount, start_balance); + + if (bSenderHigh) + final_balance.negate(); + + // Adjust the balance on the trust line if necessary. We do this even + // if we are going to delete the line to reflect the correct balance + // at the time of deletion. + state->setFieldAmount(sfBalance, final_balance); + + if (must_delete) + { + return trustDelete( + view, + state, + bSenderHigh ? issue.account : account, + bSenderHigh ? account : issue.account, + j); + } + + view.update(state); + return tesSUCCESS; + } + + // In order to hold an IOU, a trust line *MUST* exist to track the + // balance. If it doesn't, then something is very wrong. Don't try + // to continue. + // LCOV_EXCL_START + JLOG(j.fatal()) << "redeemIOU: " << to_string(account) << " attempts to " + << "redeem " << amount.getFullText() << " but no trust line exists!"; + + return tefINTERNAL; + // LCOV_EXCL_STOP +} + +//------------------------------------------------------------------------------ +// +// Authorization and transfer checks (IOU-specific) +// +//------------------------------------------------------------------------------ + +TER +requireAuth(ReadView const& view, Issue const& issue, AccountID const& account, AuthType authType) +{ + if (isXRP(issue) || issue.account == account) + return tesSUCCESS; + + auto const trustLine = view.read(keylet::line(account, issue.account, issue.currency)); + // If account has no line, and this is a strong check, fail + if (!trustLine && authType == AuthType::StrongAuth) + return tecNO_LINE; + + // If this is a weak or legacy check, or if the account has a line, fail if + // auth is required and not set on the line + if (auto const issuerAccount = view.read(keylet::account(issue.account)); + issuerAccount && (*issuerAccount)[sfFlags] & lsfRequireAuth) + { + if (trustLine) + { + return ((*trustLine)[sfFlags] & ((account > issue.account) ? lsfLowAuth : lsfHighAuth)) + ? tesSUCCESS + : TER{tecNO_AUTH}; + } + return TER{tecNO_LINE}; + } + + return tesSUCCESS; +} + +TER +canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to) +{ + if (issue.native()) + return tesSUCCESS; + + auto const& issuerId = issue.getIssuer(); + if (issuerId == from || issuerId == to) + return tesSUCCESS; + auto const sleIssuer = view.read(keylet::account(issuerId)); + if (sleIssuer == nullptr) + return tefINTERNAL; // LCOV_EXCL_LINE + + auto const isRippleDisabled = [&](AccountID account) -> bool { + // Line might not exist, but some transfers can create it. If this + // is the case, just check the default ripple on the issuer account. + auto const line = view.read(keylet::line(account, issue)); + if (line) + { + bool const issuerHigh = issuerId > account; + return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple); + } + return sleIssuer->isFlag(lsfDefaultRipple) == false; + }; + + // Fail if rippling disabled on both trust lines + if (isRippleDisabled(from) && isRippleDisabled(to)) + return terNO_RIPPLE; + + return tesSUCCESS; +} + +//------------------------------------------------------------------------------ +// +// Empty holding operations (IOU-specific) +// +//------------------------------------------------------------------------------ + +TER +addEmptyHolding( + ApplyView& view, + AccountID const& accountID, + XRPAmount priorBalance, + Issue const& issue, + beast::Journal journal) +{ + // Every account can hold XRP. An issuer can issue directly. + if (issue.native() || accountID == issue.getIssuer()) + return tesSUCCESS; + + auto const& issuerId = issue.getIssuer(); + auto const& currency = issue.currency; + if (isGlobalFrozen(view, issuerId)) + return tecFROZEN; // LCOV_EXCL_LINE + + auto const& srcId = issuerId; + auto const& dstId = accountID; + auto const high = srcId > dstId; + auto const index = keylet::line(srcId, dstId, currency); + auto const sleSrc = view.peek(keylet::account(srcId)); + auto const sleDst = 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)) + return tecDUPLICATE; + + // 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; + + return trustCreate( + view, + high, + srcId, + dstId, + index.key, + sleDst, + /*bAuth=*/false, + /*bNoRipple=*/true, + /*bFreeze=*/false, + /*deepFreeze*/ false, + /*saBalance=*/STAmount{Issue{currency, noAccount()}}, + /*saLimit=*/STAmount{Issue{currency, dstId}}, + /*uQualityIn=*/0, + /*uQualityOut=*/0, + journal); +} + +TER +removeEmptyHolding( + ApplyView& view, + AccountID const& accountID, + Issue const& issue, + beast::Journal journal) +{ + if (issue.native()) + { + auto const sle = view.read(keylet::account(accountID)); + if (!sle) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const balance = sle->getFieldAmount(sfBalance); + if (balance.xrp() != 0) + return tecHAS_OBLIGATIONS; + + return tesSUCCESS; + } + + // `asset` is an IOU. + // 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::line(accountID, issue)); + if (!line) + return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND; + if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::zero) + return tecHAS_OBLIGATIONS; + + // Adjust the owner count(s) + if (line->isFlag(lsfLowReserve)) + { + // Clear reserve for low account. + auto sleLowAccount = view.peek(keylet::account(line->at(sfLowLimit)->getIssuer())); + if (!sleLowAccount) + return tecINTERNAL; // LCOV_EXCL_LINE + + adjustOwnerCount(view, sleLowAccount, -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); + } + + if (line->isFlag(lsfHighReserve)) + { + // Clear reserve for high account. + auto sleHighAccount = view.peek(keylet::account(line->at(sfHighLimit)->getIssuer())); + if (!sleHighAccount) + return tecINTERNAL; // LCOV_EXCL_LINE + + adjustOwnerCount(view, sleHighAccount, -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); + } + + return trustDelete( + view, line, line->at(sfLowLimit)->getIssuer(), line->at(sfHighLimit)->getIssuer(), journal); +} + +TER +deleteAMMTrustLine( + ApplyView& view, + std::shared_ptr sleState, + std::optional const& ammAccountID, + beast::Journal j) +{ + if (!sleState || sleState->getType() != ltRIPPLE_STATE) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const& [low, high] = std::minmax( + sleState->getFieldAmount(sfLowLimit).getIssuer(), + sleState->getFieldAmount(sfHighLimit).getIssuer()); + auto sleLow = view.peek(keylet::account(low)); + auto sleHigh = view.peek(keylet::account(high)); + if (!sleLow || !sleHigh) + return tecINTERNAL; // LCOV_EXCL_LINE + + bool const ammLow = sleLow->isFieldPresent(sfAMMID); + bool const ammHigh = sleHigh->isFieldPresent(sfAMMID); + + // can't both be AMM + if (ammLow && ammHigh) + return tecINTERNAL; // LCOV_EXCL_LINE + + // at least one must be + if (!ammLow && !ammHigh) + return terNO_AMM; + + // one must be the target amm + if (ammAccountID && (low != *ammAccountID && high != *ammAccountID)) + return terNO_AMM; + + if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter)) + { + JLOG(j.error()) << "deleteAMMTrustLine: failed to delete the trustline."; + return ter; + } + + auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve; + if (!(sleState->getFlags() & uFlags)) + return tecINTERNAL; // LCOV_EXCL_LINE + + adjustOwnerCount(view, !ammLow ? sleLow : sleHigh, -1, j); + + return tesSUCCESS; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/helpers/TokenHelpers.cpp b/src/libxrpl/ledger/helpers/TokenHelpers.cpp new file mode 100644 index 0000000000..7a98445b0a --- /dev/null +++ b/src/libxrpl/ledger/helpers/TokenHelpers.cpp @@ -0,0 +1,1392 @@ +#include +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xrpl { + +// Forward declaration for function that remains in View.h/cpp +bool +isLPTokenFrozen( + ReadView const& view, + AccountID const& account, + Issue const& asset, + Issue const& asset2); + +//------------------------------------------------------------------------------ +// +// Freeze checking (Asset-based) +// +//------------------------------------------------------------------------------ + +bool +isGlobalFrozen(ReadView const& view, Asset const& asset) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return isGlobalFrozen(view, issue.getIssuer()); + } + else + { + return isGlobalFrozen(view, issue); + } + }, + asset.value()); +} + +bool +isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return isIndividualFrozen(view, account, issue); }, asset.value()); +} + +bool +isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth) +{ + return std::visit( + [&](auto const& issue) { return isFrozen(view, account, issue, depth); }, asset.value()); +} + +TER +checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue) +{ + return isFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS; +} + +TER +checkFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) +{ + return isFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; +} + +TER +checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return checkFrozen(view, account, issue); }, asset.value()); +} + +bool +isAnyFrozen( + ReadView const& view, + std::initializer_list const& accounts, + Issue const& issue) +{ + for (auto const& account : accounts) + { + if (isFrozen(view, account, issue.currency, issue.account)) + return true; + } + return false; +} + +bool +isAnyFrozen( + ReadView const& view, + std::initializer_list const& accounts, + Asset const& asset, + int depth) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return isAnyFrozen(view, accounts, issue); + } + else + { + return isAnyFrozen(view, accounts, issue, depth); + } + }, + asset.value()); +} + +bool +isDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth) +{ + // Unlike IOUs, frozen / locked MPTs are not allowed to send or receive + // funds, so checking "deep frozen" is the same as checking "frozen". + return isFrozen(view, account, mptIssue, depth); +} + +bool +isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth) +{ + return std::visit( + [&](auto const& issue) { return isDeepFrozen(view, account, issue, depth); }, + asset.value()); +} + +TER +checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue) +{ + return isDeepFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS; +} + +TER +checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return checkDeepFrozen(view, account, issue); }, asset.value()); +} + +//------------------------------------------------------------------------------ +// +// Account balance functions +// +//------------------------------------------------------------------------------ + +static SLE::const_pointer +getLineIfUsable( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + FreezeHandling zeroIfFrozen, + beast::Journal j) +{ + auto const sle = view.read(keylet::line(account, issuer, currency)); + + if (!sle) + { + return nullptr; + } + + if (zeroIfFrozen == fhZERO_IF_FROZEN) + { + if (isFrozen(view, account, currency, issuer) || + isDeepFrozen(view, account, currency, issuer)) + { + return nullptr; + } + + // when fixFrozenLPTokenTransfer is enabled, if currency is lptoken, + // we need to check if the associated assets have been frozen + if (view.rules().enabled(fixFrozenLPTokenTransfer)) + { + auto const sleIssuer = view.read(keylet::account(issuer)); + if (!sleIssuer) + { + return nullptr; // LCOV_EXCL_LINE + } + if (sleIssuer->isFieldPresent(sfAMMID)) + { + auto const sleAmm = view.read(keylet::amm((*sleIssuer)[sfAMMID])); + + if (!sleAmm || + isLPTokenFrozen( + view, + account, + (*sleAmm)[sfAsset].get(), + (*sleAmm)[sfAsset2].get())) + { + return nullptr; + } + } + } + } + + return sle; +} + +static STAmount +getTrustLineBalance( + ReadView const& view, + SLE::const_ref sle, + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + bool includeOppositeLimit, + beast::Journal j) +{ + STAmount amount; + if (sle) + { + amount = sle->getFieldAmount(sfBalance); + bool const accountHigh = account > issuer; + auto const& oppositeField = accountHigh ? sfLowLimit : sfHighLimit; + if (accountHigh) + { + // Put balance in account terms. + amount.negate(); + } + if (includeOppositeLimit) + { + amount += sle->getFieldAmount(oppositeField); + } + amount.setIssuer(issuer); + } + else + { + amount.clear(Issue{currency, issuer}); + } + + JLOG(j.trace()) << "getTrustLineBalance:" << " account=" << to_string(account) + << " amount=" << amount.getFullText(); + + return view.balanceHook(account, issuer, amount); +} + +STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Currency const& currency, + AccountID const& issuer, + FreezeHandling zeroIfFrozen, + beast::Journal j, + SpendableHandling includeFullBalance) +{ + STAmount amount; + if (isXRP(currency)) + { + return {xrpLiquid(view, account, 0, j)}; + } + + bool const returnSpendable = (includeFullBalance == shFULL_BALANCE); + if (returnSpendable && account == issuer) + { + // If the account is the issuer, then their limit is effectively + // infinite + return STAmount{Issue{currency, issuer}, STAmount::cMaxValue, STAmount::cMaxOffset}; + } + + // IOU: Return balance on trust line modulo freeze + SLE::const_pointer const sle = + getLineIfUsable(view, account, currency, issuer, zeroIfFrozen, j); + + return getTrustLineBalance(view, sle, account, currency, issuer, returnSpendable, j); +} + +STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Issue const& issue, + FreezeHandling zeroIfFrozen, + beast::Journal j, + SpendableHandling includeFullBalance) +{ + return accountHolds( + view, account, issue.currency, issue.account, zeroIfFrozen, j, includeFullBalance); +} + +STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue, + FreezeHandling zeroIfFrozen, + AuthHandling zeroIfUnauthorized, + beast::Journal j, + SpendableHandling includeFullBalance) +{ + bool const returnSpendable = (includeFullBalance == shFULL_BALANCE); + + if (returnSpendable && account == mptIssue.getIssuer()) + { + // if the account is the issuer, and the issuance exists, their limit is + // the issuance limit minus the outstanding value + auto const issuance = view.read(keylet::mptIssuance(mptIssue.getMptID())); + + if (!issuance) + { + return STAmount{mptIssue}; + } + return STAmount{ + mptIssue, + issuance->at(~sfMaximumAmount).value_or(maxMPTokenAmount) - + issuance->at(sfOutstandingAmount)}; + } + + STAmount amount; + + auto const sleMpt = view.read(keylet::mptoken(mptIssue.getMptID(), account)); + + if (!sleMpt) + { + amount.clear(mptIssue); + } + else if (zeroIfFrozen == fhZERO_IF_FROZEN && isFrozen(view, account, mptIssue)) + { + amount.clear(mptIssue); + } + else + { + amount = STAmount{mptIssue, sleMpt->getFieldU64(sfMPTAmount)}; + + // Only if auth check is needed, as it needs to do an additional read + // operation. Note featureSingleAssetVault will affect error codes. + if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED && + view.rules().enabled(featureSingleAssetVault)) + { + if (auto const err = requireAuth(view, mptIssue, account, AuthType::StrongAuth); + !isTesSuccess(err)) + amount.clear(mptIssue); + } + else if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED) + { + auto const sleIssuance = view.read(keylet::mptIssuance(mptIssue.getMptID())); + + // if auth is enabled on the issuance and mpt is not authorized, + // clear amount + if (sleIssuance && sleIssuance->isFlag(lsfMPTRequireAuth) && + !sleMpt->isFlag(lsfMPTAuthorized)) + amount.clear(mptIssue); + } + } + + return amount; +} + +[[nodiscard]] STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + Asset const& asset, + FreezeHandling zeroIfFrozen, + AuthHandling zeroIfUnauthorized, + beast::Journal j, + SpendableHandling includeFullBalance) +{ + return std::visit( + [&](TIss const& value) { + if constexpr (std::is_same_v) + { + return accountHolds(view, account, value, zeroIfFrozen, j, includeFullBalance); + } + else if constexpr (std::is_same_v) + { + return accountHolds( + view, account, value, zeroIfFrozen, zeroIfUnauthorized, j, includeFullBalance); + } + }, + asset.value()); +} + +STAmount +accountFunds( + ReadView const& view, + AccountID const& id, + STAmount const& saDefault, + FreezeHandling freezeHandling, + beast::Journal j) +{ + if (!saDefault.native() && saDefault.getIssuer() == id) + return saDefault; + + return accountHolds( + view, id, saDefault.getCurrency(), saDefault.getIssuer(), freezeHandling, j); +} + +Rate +transferRate(ReadView const& view, STAmount const& amount) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return transferRate(view, issue.getIssuer()); + } + else + { + return transferRate(view, issue.getMptID()); + } + }, + amount.asset().value()); +} + +//------------------------------------------------------------------------------ +// +// Holding operations +// +//------------------------------------------------------------------------------ + +[[nodiscard]] TER +canAddHolding(ReadView const& view, Issue const& issue) +{ + if (issue.native()) + { + return tesSUCCESS; // No special checks for XRP + } + + auto const issuer = view.read(keylet::account(issue.getIssuer())); + if (!issuer) + { + return terNO_ACCOUNT; + } + if (!issuer->isFlag(lsfDefaultRipple)) + { + return terNO_RIPPLE; + } + + return tesSUCCESS; +} + +[[nodiscard]] TER +canAddHolding(ReadView const& view, Asset const& asset) +{ + return std::visit( + [&](TIss const& issue) -> TER { return canAddHolding(view, issue); }, + asset.value()); +} + +TER +addEmptyHolding( + ApplyView& view, + AccountID const& accountID, + XRPAmount priorBalance, + Asset const& asset, + beast::Journal journal) +{ + return std::visit( + [&](TIss const& issue) -> TER { + return addEmptyHolding(view, accountID, priorBalance, issue, journal); + }, + asset.value()); +} + +TER +removeEmptyHolding( + ApplyView& view, + AccountID const& accountID, + Asset const& asset, + beast::Journal journal) +{ + return std::visit( + [&](TIss const& issue) -> TER { + return removeEmptyHolding(view, accountID, issue, journal); + }, + asset.value()); +} + +//------------------------------------------------------------------------------ +// +// Authorization and transfer checks +// +//------------------------------------------------------------------------------ + +TER +requireAuth(ReadView const& view, Asset const& asset, AccountID const& account, AuthType authType) +{ + return std::visit( + [&](TIss const& issue_) { + return requireAuth(view, issue_, account, authType); + }, + asset.value()); +} + +TER +canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, AccountID const& to) +{ + return std::visit( + [&](TIss const& issue) -> TER { + return canTransfer(view, issue, from, to); + }, + asset.value()); +} + +//------------------------------------------------------------------------------ +// +// Money Transfers +// +//------------------------------------------------------------------------------ + +// Direct send w/o fees: +// - Redeeming IOUs and/or sending sender's own IOUs. +// - Create trust line if needed. +// --> bCheckIssuer : normally require issuer to be involved. +static TER +rippleCreditIOU( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + bool bCheckIssuer, + beast::Journal j) +{ + AccountID const& issuer = saAmount.getIssuer(); + Currency const& currency = saAmount.getCurrency(); + + // Make sure issuer is involved. + XRPL_ASSERT( + !bCheckIssuer || uSenderID == issuer || uReceiverID == issuer, + "xrpl::rippleCreditIOU : matching issuer or don't care"); + (void)issuer; + + // Disallow sending to self. + XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleCreditIOU : sender is not receiver"); + + bool const bSenderHigh = uSenderID > uReceiverID; + auto const index = keylet::line(uSenderID, uReceiverID, currency); + + XRPL_ASSERT( + !isXRP(uSenderID) && uSenderID != noAccount(), "xrpl::rippleCreditIOU : sender is not XRP"); + XRPL_ASSERT( + !isXRP(uReceiverID) && uReceiverID != noAccount(), + "xrpl::rippleCreditIOU : receiver is not XRP"); + + // If the line exists, modify it accordingly. + if (auto const sleRippleState = view.peek(index)) + { + STAmount saBalance = sleRippleState->getFieldAmount(sfBalance); + + if (bSenderHigh) + saBalance.negate(); // Put balance in sender terms. + + view.creditHook(uSenderID, uReceiverID, saAmount, saBalance); + + STAmount const saBefore = saBalance; + + saBalance -= saAmount; + + JLOG(j.trace()) << "rippleCreditIOU: " << to_string(uSenderID) << " -> " + << to_string(uReceiverID) << " : before=" << saBefore.getFullText() + << " amount=" << saAmount.getFullText() + << " after=" << saBalance.getFullText(); + + std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags)); + bool bDelete = false; + + // FIXME This NEEDS to be cleaned up and simplified. It's impossible + // for anyone to understand. + if (saBefore > beast::zero + // Sender balance was positive. + && saBalance <= beast::zero + // Sender is zero or negative. + && (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) + // Sender reserve is set. + && static_cast(uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) != + static_cast( + view.read(keylet::account(uSenderID))->getFlags() & lsfDefaultRipple) && + !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) && + !sleRippleState->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) + // Sender trust limit is 0. + && !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) + // Sender quality in is 0. + && !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) + // Sender quality out is 0. + { + // Clear the reserve of the sender, possibly delete the line! + adjustOwnerCount(view, view.peek(keylet::account(uSenderID)), -1, j); + + // Clear reserve flag. + sleRippleState->setFieldU32( + sfFlags, uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); + + // Balance is zero, receiver reserve is clear. + bDelete = !saBalance // Balance is zero. + && !(uFlags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)); + // Receiver reserve is clear. + } + + if (bSenderHigh) + saBalance.negate(); + + // Want to reflect balance to zero even if we are deleting line. + sleRippleState->setFieldAmount(sfBalance, saBalance); + // ONLY: Adjust ripple balance. + + if (bDelete) + { + return trustDelete( + view, + sleRippleState, + bSenderHigh ? uReceiverID : uSenderID, + !bSenderHigh ? uReceiverID : uSenderID, + j); + } + + view.update(sleRippleState); + return tesSUCCESS; + } + + STAmount const saReceiverLimit(Issue{currency, uReceiverID}); + STAmount saBalance{saAmount}; + + saBalance.setIssuer(noAccount()); + + JLOG(j.debug()) << "rippleCreditIOU: " + "create line: " + << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : " + << saAmount.getFullText(); + + auto const sleAccount = view.peek(keylet::account(uReceiverID)); + if (!sleAccount) + return tefINTERNAL; // LCOV_EXCL_LINE + + bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0; + + return trustCreate( + view, + bSenderHigh, + uSenderID, + uReceiverID, + index.key, + sleAccount, + false, + noRipple, + false, + false, + saBalance, + saReceiverLimit, + 0, + 0, + j); +} + +// Send regardless of limits. +// --> saAmount: Amount/currency/issuer to deliver to receiver. +// <-- saActual: Amount actually cost. Sender pays fees. +static TER +rippleSendIOU( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + STAmount& saActual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + auto const& issuer = saAmount.getIssuer(); + + XRPL_ASSERT( + !isXRP(uSenderID) && !isXRP(uReceiverID), + "xrpl::rippleSendIOU : neither sender nor receiver is XRP"); + XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleSendIOU : sender is not receiver"); + + if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount()) + { + // Direct send: redeeming IOUs and/or sending own IOUs. + auto const ter = rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, false, j); + if (!isTesSuccess(ter)) + return ter; + saActual = saAmount; + return tesSUCCESS; + } + + // Sending 3rd party IOUs: transit. + + // Calculate the amount to transfer accounting + // for any transfer fees if the fee is not waived: + saActual = (waiveFee == WaiveTransferFee::Yes) ? saAmount + : multiply(saAmount, transferRate(view, issuer)); + + JLOG(j.debug()) << "rippleSendIOU> " << to_string(uSenderID) << " - > " + << to_string(uReceiverID) << " : deliver=" << saAmount.getFullText() + << " cost=" << saActual.getFullText(); + + TER terResult = rippleCreditIOU(view, issuer, uReceiverID, saAmount, true, j); + + if (tesSUCCESS == terResult) + terResult = rippleCreditIOU(view, uSenderID, issuer, saActual, true, j); + + return terResult; +} + +// Send regardless of limits. +// --> receivers: Amount/currency/issuer to deliver to receivers. +// <-- saActual: Amount actually cost to sender. Sender pays fees. +static TER +rippleSendMultiIOU( + ApplyView& view, + AccountID const& senderID, + Issue const& issue, + MultiplePaymentDestinations const& receivers, + STAmount& actual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + auto const& issuer = issue.getIssuer(); + + XRPL_ASSERT(!isXRP(senderID), "xrpl::rippleSendMultiIOU : sender is not XRP"); + + // These may diverge + STAmount takeFromSender{issue}; + actual = takeFromSender; + + // Failures return immediately. + for (auto const& r : receivers) + { + auto const& receiverID = r.first; + STAmount amount{issue, r.second}; + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!amount || (senderID == receiverID)) + continue; + + XRPL_ASSERT(!isXRP(receiverID), "xrpl::rippleSendMultiIOU : receiver is not XRP"); + + if (senderID == issuer || receiverID == issuer || issuer == noAccount()) + { + // Direct send: redeeming IOUs and/or sending own IOUs. + if (auto const ter = rippleCreditIOU(view, senderID, receiverID, amount, false, j)) + return ter; + actual += amount; + // Do not add amount to takeFromSender, because rippleCreditIOU took + // it. + + continue; + } + + // Sending 3rd party IOUs: transit. + + // Calculate the amount to transfer accounting + // for any transfer fees if the fee is not waived: + STAmount actualSend = (waiveFee == WaiveTransferFee::Yes) + ? amount + : multiply(amount, transferRate(view, issuer)); + actual += actualSend; + takeFromSender += actualSend; + + JLOG(j.debug()) << "rippleSendMultiIOU> " << to_string(senderID) << " - > " + << to_string(receiverID) << " : deliver=" << amount.getFullText() + << " cost=" << actual.getFullText(); + + if (TER const terResult = rippleCreditIOU(view, issuer, receiverID, amount, true, j)) + return terResult; + } + + if (senderID != issuer && takeFromSender) + { + if (TER const terResult = rippleCreditIOU(view, senderID, issuer, takeFromSender, true, j)) + return terResult; + } + + return tesSUCCESS; +} + +static TER +accountSendIOU( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + if (view.rules().enabled(fixAMMv1_1)) + { + if (saAmount < beast::zero || saAmount.holds()) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + } + else + { + // LCOV_EXCL_START + XRPL_ASSERT( + saAmount >= beast::zero && !saAmount.holds(), + "xrpl::accountSendIOU : minimum amount and not MPT"); + // LCOV_EXCL_STOP + } + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!saAmount || (uSenderID == uReceiverID)) + return tesSUCCESS; + + if (!saAmount.native()) + { + STAmount saActual; + + JLOG(j.trace()) << "accountSendIOU: " << to_string(uSenderID) << " -> " + << to_string(uReceiverID) << " : " << saAmount.getFullText(); + + return rippleSendIOU(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); + } + + /* XRP send which does not check reserve and can do pure adjustment. + * Note that sender or receiver may be null and this not a mistake; this + * setup is used during pathfinding and it is carefully controlled to + * ensure that transfers are balanced. + */ + TER terResult(tesSUCCESS); + + SLE::pointer sender = + uSenderID != beast::zero ? view.peek(keylet::account(uSenderID)) : SLE::pointer(); + SLE::pointer receiver = + uReceiverID != beast::zero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer(); + + if (auto stream = j.trace()) + { + std::string sender_bal("-"); + std::string receiver_bal("-"); + + if (sender) + sender_bal = sender->getFieldAmount(sfBalance).getFullText(); + + if (receiver) + receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendIOU> " << to_string(uSenderID) << " (" << sender_bal << ") -> " + << to_string(uReceiverID) << " (" << receiver_bal + << ") : " << saAmount.getFullText(); + } + + if (sender) + { + if (sender->getFieldAmount(sfBalance) < saAmount) + { + // VFALCO Its laborious to have to mutate the + // TER based on params everywhere + // LCOV_EXCL_START + terResult = view.open() ? TER{telFAILED_PROCESSING} : TER{tecFAILED_PROCESSING}; + // LCOV_EXCL_STOP + } + else + { + auto const sndBal = sender->getFieldAmount(sfBalance); + view.creditHook(uSenderID, xrpAccount(), saAmount, sndBal); + + // Decrement XRP balance. + sender->setFieldAmount(sfBalance, sndBal - saAmount); + view.update(sender); + } + } + + if (tesSUCCESS == terResult && receiver) + { + // Increment XRP balance. + auto const rcvBal = receiver->getFieldAmount(sfBalance); + receiver->setFieldAmount(sfBalance, rcvBal + saAmount); + view.creditHook(xrpAccount(), uReceiverID, saAmount, -rcvBal); + + view.update(receiver); + } + + if (auto stream = j.trace()) + { + std::string sender_bal("-"); + std::string receiver_bal("-"); + + if (sender) + sender_bal = sender->getFieldAmount(sfBalance).getFullText(); + + if (receiver) + receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendIOU< " << to_string(uSenderID) << " (" << sender_bal << ") -> " + << to_string(uReceiverID) << " (" << receiver_bal + << ") : " << saAmount.getFullText(); + } + + return terResult; +} + +static TER +accountSendMultiIOU( + ApplyView& view, + AccountID const& senderID, + Issue const& issue, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + XRPL_ASSERT_PARTS( + receivers.size() > 1, "xrpl::accountSendMultiIOU", "multiple recipients provided"); + + if (!issue.native()) + { + STAmount actual; + JLOG(j.trace()) << "accountSendMultiIOU: " << to_string(senderID) << " sending " + << receivers.size() << " IOUs"; + + return rippleSendMultiIOU(view, senderID, issue, receivers, actual, j, waiveFee); + } + + /* XRP send which does not check reserve and can do pure adjustment. + * Note that sender or receiver may be null and this not a mistake; this + * setup could be used during pathfinding and it is carefully controlled to + * ensure that transfers are balanced. + */ + + SLE::pointer sender = + senderID != beast::zero ? view.peek(keylet::account(senderID)) : SLE::pointer(); + + if (auto stream = j.trace()) + { + std::string sender_bal("-"); + + if (sender) + sender_bal = sender->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU> " << to_string(senderID) << " (" << sender_bal << ") -> " + << receivers.size() << " receivers."; + } + + // Failures return immediately. + STAmount takeFromSender{issue}; + for (auto const& r : receivers) + { + auto const& receiverID = r.first; + STAmount amount{issue, r.second}; + + if (amount < beast::zero) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!amount || (senderID == receiverID)) + continue; + + SLE::pointer receiver = + receiverID != beast::zero ? view.peek(keylet::account(receiverID)) : SLE::pointer(); + + if (auto stream = j.trace()) + { + std::string receiver_bal("-"); + + if (receiver) + receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU> " << to_string(senderID) << " -> " + << to_string(receiverID) << " (" << receiver_bal + << ") : " << amount.getFullText(); + } + + if (receiver) + { + // Increment XRP balance. + auto const rcvBal = receiver->getFieldAmount(sfBalance); + receiver->setFieldAmount(sfBalance, rcvBal + amount); + view.creditHook(xrpAccount(), receiverID, amount, -rcvBal); + + view.update(receiver); + + // Take what is actually sent + takeFromSender += amount; + } + + if (auto stream = j.trace()) + { + std::string receiver_bal("-"); + + if (receiver) + receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU< " << to_string(senderID) << " -> " + << to_string(receiverID) << " (" << receiver_bal + << ") : " << amount.getFullText(); + } + } + + if (sender) + { + if (sender->getFieldAmount(sfBalance) < takeFromSender) + { + return TER{tecFAILED_PROCESSING}; + } + auto const sndBal = sender->getFieldAmount(sfBalance); + view.creditHook(senderID, xrpAccount(), takeFromSender, sndBal); + + // Decrement XRP balance. + sender->setFieldAmount(sfBalance, sndBal - takeFromSender); + view.update(sender); + } + + if (auto stream = j.trace()) + { + std::string sender_bal("-"); + + if (sender) + sender_bal = sender->getFieldAmount(sfBalance).getFullText(); + + stream << "accountSendMultiIOU< " << to_string(senderID) << " (" << sender_bal << ") -> " + << receivers.size() << " receivers."; + } + return tesSUCCESS; +} + +static TER +rippleCreditMPT( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j) +{ + // Do not check MPT authorization here - it must have been checked earlier + auto const mptID = keylet::mptIssuance(saAmount.get().getMptID()); + auto const& issuer = saAmount.getIssuer(); + auto sleIssuance = view.peek(mptID); + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + if (uSenderID == issuer) + { + (*sleIssuance)[sfOutstandingAmount] += saAmount.mpt().value(); + view.update(sleIssuance); + } + else + { + auto const mptokenID = keylet::mptoken(mptID.key, uSenderID); + if (auto sle = view.peek(mptokenID)) + { + auto const amt = sle->getFieldU64(sfMPTAmount); + auto const pay = saAmount.mpt().value(); + if (amt < pay) + return tecINSUFFICIENT_FUNDS; + (*sle)[sfMPTAmount] = amt - pay; + view.update(sle); + } + else + { + return tecNO_AUTH; + } + } + + if (uReceiverID == issuer) + { + auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); + auto const redeem = saAmount.mpt().value(); + if (outstanding >= redeem) + { + sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem); + view.update(sleIssuance); + } + else + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + } + else + { + auto const mptokenID = keylet::mptoken(mptID.key, uReceiverID); + if (auto sle = view.peek(mptokenID)) + { + (*sle)[sfMPTAmount] += saAmount.mpt().value(); + view.update(sle); + } + else + { + return tecNO_AUTH; + } + } + + return tesSUCCESS; +} + +static TER +rippleSendMPT( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + STAmount& saActual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::rippleSendMPT : sender is not receiver"); + + // Safe to get MPT since rippleSendMPT is only called by accountSendMPT + auto const& issuer = saAmount.getIssuer(); + + auto const sle = view.read(keylet::mptIssuance(saAmount.get().getMptID())); + if (!sle) + return tecOBJECT_NOT_FOUND; + + if (uSenderID == issuer || uReceiverID == issuer) + { + // if sender is issuer, check that the new OutstandingAmount will not + // exceed MaximumAmount + if (uSenderID == issuer) + { + auto const sendAmount = saAmount.mpt().value(); + auto const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); + if (sendAmount > maximumAmount || + sle->getFieldU64(sfOutstandingAmount) > maximumAmount - sendAmount) + return tecPATH_DRY; + } + + // Direct send: redeeming MPTs and/or sending own MPTs. + auto const ter = rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); + if (!isTesSuccess(ter)) + return ter; + saActual = saAmount; + return tesSUCCESS; + } + + // Sending 3rd party MPTs: transit. + saActual = (waiveFee == WaiveTransferFee::Yes) + ? saAmount + : multiply(saAmount, transferRate(view, saAmount.get().getMptID())); + + JLOG(j.debug()) << "rippleSendMPT> " << to_string(uSenderID) << " - > " + << to_string(uReceiverID) << " : deliver=" << saAmount.getFullText() + << " cost=" << saActual.getFullText(); + + if (auto const terResult = rippleCreditMPT(view, issuer, uReceiverID, saAmount, j); + !isTesSuccess(terResult)) + return terResult; + + return rippleCreditMPT(view, uSenderID, issuer, saActual, j); +} + +static TER +rippleSendMultiMPT( + ApplyView& view, + AccountID const& senderID, + MPTIssue const& mptIssue, + MultiplePaymentDestinations const& receivers, + STAmount& actual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + // Safe to get MPT since rippleSendMultiMPT is only called by + // accountSendMultiMPT + auto const& issuer = mptIssue.getIssuer(); + + auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID())); + if (!sle) + return tecOBJECT_NOT_FOUND; + + // These may diverge + STAmount takeFromSender{mptIssue}; + actual = takeFromSender; + + for (auto const& r : receivers) + { + auto const& receiverID = r.first; + STAmount amount{mptIssue, r.second}; + + if (amount < beast::zero) + { + return tecINTERNAL; // LCOV_EXCL_LINE + } + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!amount || (senderID == receiverID)) + continue; + + if (senderID == issuer || receiverID == issuer) + { + // if sender is issuer, check that the new OutstandingAmount will + // not exceed MaximumAmount + if (senderID == issuer) + { + XRPL_ASSERT_PARTS( + takeFromSender == beast::zero, + "xrpl::rippleSendMultiMPT", + "sender == issuer, takeFromSender == zero"); + auto const sendAmount = amount.mpt().value(); + auto const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); + if (sendAmount > maximumAmount || + sle->getFieldU64(sfOutstandingAmount) > maximumAmount - sendAmount) + return tecPATH_DRY; + } + + // Direct send: redeeming MPTs and/or sending own MPTs. + if (auto const ter = rippleCreditMPT(view, senderID, receiverID, amount, j)) + return ter; + actual += amount; + // Do not add amount to takeFromSender, because rippleCreditMPT took + // it + + continue; + } + + // Sending 3rd party MPTs: transit. + STAmount actualSend = (waiveFee == WaiveTransferFee::Yes) + ? amount + : multiply(amount, transferRate(view, amount.get().getMptID())); + actual += actualSend; + takeFromSender += actualSend; + + JLOG(j.debug()) << "rippleSendMultiMPT> " << to_string(senderID) << " - > " + << to_string(receiverID) << " : deliver=" << amount.getFullText() + << " cost=" << actualSend.getFullText(); + + if (auto const terResult = rippleCreditMPT(view, issuer, receiverID, amount, j)) + return terResult; + } + if (senderID != issuer && takeFromSender) + { + if (TER const terResult = rippleCreditMPT(view, senderID, issuer, takeFromSender, j)) + return terResult; + } + + return tesSUCCESS; +} + +static TER +accountSendMPT( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + XRPL_ASSERT( + saAmount >= beast::zero && saAmount.holds(), + "xrpl::accountSendMPT : minimum amount and MPT"); + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!saAmount || (uSenderID == uReceiverID)) + return tesSUCCESS; + + STAmount saActual{saAmount.asset()}; + + return rippleSendMPT(view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); +} + +static TER +accountSendMultiMPT( + ApplyView& view, + AccountID const& senderID, + MPTIssue const& mptIssue, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + STAmount actual; + + return rippleSendMultiMPT(view, senderID, mptIssue, receivers, actual, j, waiveFee); +} + +//------------------------------------------------------------------------------ +// +// Public Dispatcher Functions +// +//------------------------------------------------------------------------------ + +TER +rippleCredit( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + bool bCheckIssuer, + beast::Journal j) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j); + } + else + { + XRPL_ASSERT(!bCheckIssuer, "xrpl::rippleCredit : not checking issuer"); + return rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); + } + }, + saAmount.asset().value()); +} + +TER +accountSend( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return accountSendIOU(view, uSenderID, uReceiverID, saAmount, j, waiveFee); + } + else + { + return accountSendMPT(view, uSenderID, uReceiverID, saAmount, j, waiveFee); + } + }, + saAmount.asset().value()); +} + +TER +accountSendMulti( + ApplyView& view, + AccountID const& senderID, + Asset const& asset, + MultiplePaymentDestinations const& receivers, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + XRPL_ASSERT_PARTS( + receivers.size() > 1, "xrpl::accountSendMulti", "multiple recipients provided"); + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return accountSendMultiIOU(view, senderID, issue, receivers, j, waiveFee); + } + else + { + return accountSendMultiMPT(view, senderID, issue, receivers, j, waiveFee); + } + }, + asset.value()); +} + +TER +transferXRP( + ApplyView& view, + AccountID const& from, + AccountID const& to, + STAmount const& amount, + beast::Journal j) +{ + XRPL_ASSERT(from != beast::zero, "xrpl::transferXRP : nonzero from account"); + XRPL_ASSERT(to != beast::zero, "xrpl::transferXRP : nonzero to account"); + XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver"); + XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP"); + + SLE::pointer const sender = view.peek(keylet::account(from)); + SLE::pointer const receiver = view.peek(keylet::account(to)); + if (!sender || !receiver) + return tefINTERNAL; // LCOV_EXCL_LINE + + JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> " << to_string(to) + << ") : " << amount.getFullText(); + + if (sender->getFieldAmount(sfBalance) < amount) + { + // VFALCO Its unfortunate we have to keep + // mutating these TER everywhere + // FIXME: this logic should be moved to callers maybe? + // LCOV_EXCL_START + return view.open() ? TER{telFAILED_PROCESSING} : TER{tecFAILED_PROCESSING}; + // LCOV_EXCL_STOP + } + + // Decrement XRP balance. + sender->setFieldAmount(sfBalance, sender->getFieldAmount(sfBalance) - amount); + view.update(sender); + + receiver->setFieldAmount(sfBalance, receiver->getFieldAmount(sfBalance) + amount); + view.update(receiver); + + return tesSUCCESS; +} + +} // namespace xrpl diff --git a/src/libxrpl/ledger/helpers/VaultHelpers.cpp b/src/libxrpl/ledger/helpers/VaultHelpers.cpp new file mode 100644 index 0000000000..3ded720289 --- /dev/null +++ b/src/libxrpl/ledger/helpers/VaultHelpers.cpp @@ -0,0 +1,112 @@ +#include +// +#include +#include +#include + +namespace xrpl { + +[[nodiscard]] std::optional +assetsToSharesDeposit( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& assets) +{ + XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets"); + XRPL_ASSERT( + assets.asset() == vault->at(sfAsset), + "xrpl::assetsToSharesDeposit : assets and vault match"); + if (assets.negative() || assets.asset() != vault->at(sfAsset)) + return std::nullopt; // LCOV_EXCL_LINE + + Number const assetTotal = vault->at(sfAssetsTotal); + STAmount shares{vault->at(sfShareMPTID)}; + if (assetTotal == 0) + { + return STAmount{ + shares.asset(), + Number(assets.mantissa(), assets.exponent() + vault->at(sfScale)).truncate()}; + } + + Number const shareTotal = issuance->at(sfOutstandingAmount); + shares = ((shareTotal * assets) / assetTotal).truncate(); + return shares; +} + +[[nodiscard]] std::optional +sharesToAssetsDeposit( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& shares) +{ + XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares"); + XRPL_ASSERT( + shares.asset() == vault->at(sfShareMPTID), + "xrpl::sharesToAssetsDeposit : shares and vault match"); + if (shares.negative() || shares.asset() != vault->at(sfShareMPTID)) + return std::nullopt; // LCOV_EXCL_LINE + + Number const assetTotal = vault->at(sfAssetsTotal); + STAmount assets{vault->at(sfAsset)}; + if (assetTotal == 0) + { + return STAmount{ + assets.asset(), shares.mantissa(), shares.exponent() - vault->at(sfScale), false}; + } + + Number const shareTotal = issuance->at(sfOutstandingAmount); + assets = (assetTotal * shares) / shareTotal; + return assets; +} + +[[nodiscard]] std::optional +assetsToSharesWithdraw( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& assets, + TruncateShares truncate) +{ + XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesWithdraw : non-negative assets"); + XRPL_ASSERT( + assets.asset() == vault->at(sfAsset), + "xrpl::assetsToSharesWithdraw : assets and vault match"); + if (assets.negative() || assets.asset() != vault->at(sfAsset)) + return std::nullopt; // LCOV_EXCL_LINE + + Number assetTotal = vault->at(sfAssetsTotal); + assetTotal -= vault->at(sfLossUnrealized); + STAmount shares{vault->at(sfShareMPTID)}; + if (assetTotal == 0) + return shares; + Number const shareTotal = issuance->at(sfOutstandingAmount); + Number result = (shareTotal * assets) / assetTotal; + if (truncate == TruncateShares::yes) + result = result.truncate(); + shares = result; + return shares; +} + +[[nodiscard]] std::optional +sharesToAssetsWithdraw( + std::shared_ptr const& vault, + std::shared_ptr const& issuance, + STAmount const& shares) +{ + XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares"); + XRPL_ASSERT( + shares.asset() == vault->at(sfShareMPTID), + "xrpl::sharesToAssetsWithdraw : shares and vault match"); + if (shares.negative() || shares.asset() != vault->at(sfShareMPTID)) + return std::nullopt; // LCOV_EXCL_LINE + + Number assetTotal = vault->at(sfAssetsTotal); + assetTotal -= vault->at(sfLossUnrealized); + STAmount assets{vault->at(sfAsset)}; + if (assetTotal == 0) + return assets; + Number const shareTotal = issuance->at(sfOutstandingAmount); + assets = (assetTotal * shares) / shareTotal; + return assets; +} + +} // namespace xrpl diff --git a/src/libxrpl/tx/Transactor.cpp b/src/libxrpl/tx/Transactor.cpp index ff42441e2f..1c937f9380 100644 --- a/src/libxrpl/tx/Transactor.cpp +++ b/src/libxrpl/tx/Transactor.cpp @@ -2,8 +2,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp b/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp index d4cbe81f9b..02eaee0552 100644 --- a/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp +++ b/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp @@ -1,7 +1,7 @@ #include // #include -#include +#include #include #include #include diff --git a/src/libxrpl/tx/paths/Flow.cpp b/src/libxrpl/tx/paths/Flow.cpp index fc33585179..5a706ea812 100644 --- a/src/libxrpl/tx/paths/Flow.cpp +++ b/src/libxrpl/tx/paths/Flow.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/account/AccountDelete.cpp b/src/libxrpl/tx/transactors/account/AccountDelete.cpp index b50b254ec9..822b6121de 100644 --- a/src/libxrpl/tx/transactors/account/AccountDelete.cpp +++ b/src/libxrpl/tx/transactors/account/AccountDelete.cpp @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp index 1c5608c09f..26ecf311fe 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp index 5dafd146c7..8d70e00d43 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/credentials/CredentialDelete.cpp b/src/libxrpl/tx/transactors/credentials/CredentialDelete.cpp index d273135aa9..5f78ba6757 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialDelete.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialDelete.cpp @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/dex/PermissionedDEXHelpers.cpp b/src/libxrpl/tx/transactors/dex/PermissionedDEXHelpers.cpp index 37db2d632f..d857795e39 100644 --- a/src/libxrpl/tx/transactors/dex/PermissionedDEXHelpers.cpp +++ b/src/libxrpl/tx/transactors/dex/PermissionedDEXHelpers.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace xrpl { diff --git a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp index 680a20a077..e85b00e606 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp index 57d9cbc173..ca64c6bb56 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp @@ -1,6 +1,6 @@ #include // -#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp index 2b9a8dfd3a..55a27e28ed 100644 --- a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp +++ b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment/Payment.cpp b/src/libxrpl/tx/transactors/payment/Payment.cpp index 8bf86b7b38..6fc6d995fa 100644 --- a/src/libxrpl/tx/transactors/payment/Payment.cpp +++ b/src/libxrpl/tx/transactors/payment/Payment.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp index a97b4c9e56..6ba489bbc3 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp index c27c884b10..f4d4f6a805 100644 --- a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp +++ b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp @@ -1,7 +1,7 @@ #include // -#include #include +#include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp index 66f4fb09b8..bceaa354a1 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index a473ac7c36..2507563bde 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include diff --git a/src/test/app/Credentials_test.cpp b/src/test/app/Credentials_test.cpp index 3c3d8b6df8..d23431f68e 100644 --- a/src/test/app/Credentials_test.cpp +++ b/src/test/app/Credentials_test.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index a07e5824d6..142f07bf73 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -1,8 +1,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index 6eaa0d04c4..e37a184e07 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -1,8 +1,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/DepositAuthorized.cpp b/src/xrpld/rpc/handlers/DepositAuthorized.cpp index 7ab7e30c8a..080b136964 100644 --- a/src/xrpld/rpc/handlers/DepositAuthorized.cpp +++ b/src/xrpld/rpc/handlers/DepositAuthorized.cpp @@ -1,8 +1,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 8e3b7f214d..640369c04b 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include #include #include From dcfcdab14e7944ac4a2a93af8844bec3ec01b7f6 Mon Sep 17 00:00:00 2001 From: Olek <115580134+oleks-rip@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:29:34 -0400 Subject: [PATCH 14/16] fix: Remove superfluous view update from credentials (#6545) --- .../tx/transactors/credentials/CredentialCreate.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp index 8d70e00d43..af5c786c59 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp @@ -146,14 +146,15 @@ CredentialCreate::doApply() } else { + // Added to both dirs, owned only by issuer. CredentialAccept will transfer ownership to + // subject. CredentialDelete will remove from both dirs and decrement 1 ownerCount. auto const page = view().dirInsert(keylet::ownerDir(subject), credentialKey, describeOwnerDir(subject)); - JLOG(j_.trace()) << "Adding Credential to owner directory " << to_string(credentialKey.key) - << ": " << (page ? "success" : "failure"); + JLOG(j_.trace()) << "Adding Credential to subject directory " + << to_string(credentialKey.key) << ": " << (page ? "success" : "failure"); if (!page) return tecDIR_FULL; sleCred->setFieldU64(sfSubjectNode, *page); - view().update(view().peek(keylet::account(subject))); } view().insert(sleCred); From 8b986e4ab0bceae1310f10ee43bcbce35034f4c6 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 24 Mar 2026 03:20:32 -0700 Subject: [PATCH 15/16] refactor: Improve imports to only call the needed helpers (#6624) --- include/xrpl/ledger/View.h | 19 +++++-------------- include/xrpl/tx/paths/detail/StrandFlow.h | 1 + include/xrpl/tx/transactors/dex/AMMUtils.h | 1 + include/xrpl/tx/transactors/dex/AMMWithdraw.h | 1 + src/libxrpl/ledger/AcceptedLedgerTx.cpp | 1 + src/libxrpl/ledger/BookDirs.cpp | 1 + src/libxrpl/ledger/View.cpp | 3 +++ src/libxrpl/tx/Transactor.cpp | 3 +++ src/libxrpl/tx/invariants/InvariantCheck.cpp | 2 ++ src/libxrpl/tx/invariants/LoanInvariant.cpp | 1 + src/libxrpl/tx/invariants/VaultInvariant.cpp | 1 + src/libxrpl/tx/paths/BookTip.cpp | 2 ++ src/libxrpl/tx/paths/OfferStream.cpp | 2 ++ .../tx/transactors/account/AccountDelete.cpp | 2 ++ .../tx/transactors/account/AccountSet.cpp | 1 + .../tx/transactors/account/SignerListSet.cpp | 3 ++- .../tx/transactors/bridge/XChainBridge.cpp | 3 ++- .../tx/transactors/check/CheckCancel.cpp | 1 + .../tx/transactors/check/CheckCash.cpp | 2 ++ .../tx/transactors/check/CheckCreate.cpp | 3 +++ .../credentials/CredentialAccept.cpp | 2 +- .../credentials/CredentialCreate.cpp | 3 ++- .../tx/transactors/delegate/DelegateSet.cpp | 2 ++ src/libxrpl/tx/transactors/dex/AMMCreate.cpp | 1 + src/libxrpl/tx/transactors/dex/AMMDeposit.cpp | 1 + .../tx/transactors/dex/OfferCancel.cpp | 1 + .../tx/transactors/dex/OfferCreate.cpp | 4 ++++ src/libxrpl/tx/transactors/did/DIDDelete.cpp | 2 +- src/libxrpl/tx/transactors/did/DIDSet.cpp | 3 ++- .../tx/transactors/escrow/EscrowCancel.cpp | 4 ++++ .../tx/transactors/escrow/EscrowCreate.cpp | 5 +++++ .../tx/transactors/escrow/EscrowFinish.cpp | 3 +++ .../tx/transactors/escrow/EscrowHelpers.h | 4 ++++ .../lending/LoanBrokerCoverClawback.cpp | 1 + .../lending/LoanBrokerCoverDeposit.cpp | 1 + .../lending/LoanBrokerCoverWithdraw.cpp | 2 ++ .../transactors/lending/LoanBrokerDelete.cpp | 2 ++ .../tx/transactors/lending/LoanBrokerSet.cpp | 2 ++ .../tx/transactors/lending/LoanDelete.cpp | 1 + .../tx/transactors/lending/LoanManage.cpp | 1 + .../tx/transactors/lending/LoanPay.cpp | 1 + .../tx/transactors/lending/LoanSet.cpp | 2 ++ .../tx/transactors/nft/NFTokenAcceptOffer.cpp | 1 + .../tx/transactors/nft/NFTokenUtils.cpp | 4 ++++ .../tx/transactors/oracle/OracleDelete.cpp | 1 + .../tx/transactors/oracle/OracleSet.cpp | 2 ++ .../tx/transactors/payment/DepositPreauth.cpp | 2 ++ .../tx/transactors/payment/Payment.cpp | 4 ++++ .../payment_channel/PaymentChannelCreate.cpp | 2 ++ .../payment_channel/PaymentChannelHelpers.cpp | 1 + .../PermissionedDomainDelete.cpp | 1 + .../PermissionedDomainSet.cpp | 2 ++ .../tx/transactors/system/TicketCreate.cpp | 2 ++ src/libxrpl/tx/transactors/token/Clawback.cpp | 2 ++ .../tx/transactors/token/MPTokenAuthorize.cpp | 3 +++ .../token/MPTokenIssuanceCreate.cpp | 2 ++ .../token/MPTokenIssuanceDestroy.cpp | 1 + src/libxrpl/tx/transactors/token/TrustSet.cpp | 2 ++ .../tx/transactors/vault/VaultClawback.cpp | 2 ++ .../tx/transactors/vault/VaultCreate.cpp | 3 +++ .../tx/transactors/vault/VaultDelete.cpp | 3 +++ .../tx/transactors/vault/VaultDeposit.cpp | 3 +++ .../tx/transactors/vault/VaultWithdraw.cpp | 2 ++ src/test/app/AMM_test.cpp | 1 + src/test/app/AccountSet_test.cpp | 1 + src/test/app/Check_test.cpp | 1 + src/test/app/FeeVote_test.cpp | 2 +- src/test/app/Flow_test.cpp | 1 + src/test/app/Invariants_test.cpp | 3 +++ src/test/app/Vault_test.cpp | 3 ++- src/test/consensus/NegativeUNL_test.cpp | 2 +- src/test/jtx/PathSet.h | 1 + src/test/jtx/impl/TestHelpers.cpp | 1 + src/test/jtx/impl/mpt.cpp | 1 + src/test/jtx/impl/owners.cpp | 2 ++ src/test/jtx/owners.h | 2 +- src/test/ledger/Directory_test.cpp | 1 + src/test/ledger/PaymentSandbox_test.cpp | 3 ++- src/test/ledger/View_test.cpp | 2 ++ src/test/rpc/Book_test.cpp | 1 + src/xrpld/app/ledger/detail/LedgerToJson.cpp | 1 + src/xrpld/app/misc/NetworkOPs.cpp | 4 ++++ src/xrpld/app/paths/AMMOffer.h | 1 + src/xrpld/app/paths/TrustLine.cpp | 1 + src/xrpld/app/paths/detail/BookStep.cpp | 1 + src/xrpld/app/paths/detail/DirectStep.cpp | 1 + .../app/paths/detail/XRPEndpointStep.cpp | 1 + src/xrpld/rpc/handlers/AccountChannels.cpp | 1 + src/xrpld/rpc/handlers/AccountInfo.cpp | 1 + src/xrpld/rpc/handlers/AccountLines.cpp | 1 + src/xrpld/rpc/handlers/AccountOffers.cpp | 1 + src/xrpld/rpc/handlers/GatewayBalances.cpp | 1 + src/xrpld/rpc/handlers/NFTOffers.cpp | 1 + src/xrpld/rpc/handlers/NoRippleCheck.cpp | 1 + 94 files changed, 166 insertions(+), 25 deletions(-) diff --git a/include/xrpl/ledger/View.h b/include/xrpl/ledger/View.h index 2ea38c5b8b..55be01d677 100644 --- a/include/xrpl/ledger/View.h +++ b/include/xrpl/ledger/View.h @@ -2,28 +2,19 @@ #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include -#include -#include +#include #include +#include #include -#include #include +#include +#include +#include #include namespace xrpl { diff --git a/include/xrpl/tx/paths/detail/StrandFlow.h b/include/xrpl/tx/paths/detail/StrandFlow.h index f99f54d0e8..2a94b9b968 100644 --- a/include/xrpl/tx/paths/detail/StrandFlow.h +++ b/include/xrpl/tx/paths/detail/StrandFlow.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/include/xrpl/tx/transactors/dex/AMMUtils.h b/include/xrpl/tx/transactors/dex/AMMUtils.h index 18db7e6555..77ad18106e 100644 --- a/include/xrpl/tx/transactors/dex/AMMUtils.h +++ b/include/xrpl/tx/transactors/dex/AMMUtils.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/include/xrpl/tx/transactors/dex/AMMWithdraw.h b/include/xrpl/tx/transactors/dex/AMMWithdraw.h index c15bb68644..5328b03abb 100644 --- a/include/xrpl/tx/transactors/dex/AMMWithdraw.h +++ b/include/xrpl/tx/transactors/dex/AMMWithdraw.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace xrpl { diff --git a/src/libxrpl/ledger/AcceptedLedgerTx.cpp b/src/libxrpl/ledger/AcceptedLedgerTx.cpp index f0d243f9b6..005d48e6f6 100644 --- a/src/libxrpl/ledger/AcceptedLedgerTx.cpp +++ b/src/libxrpl/ledger/AcceptedLedgerTx.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/src/libxrpl/ledger/BookDirs.cpp b/src/libxrpl/ledger/BookDirs.cpp index 699d6c2879..2bdf6ac9a5 100644 --- a/src/libxrpl/ledger/BookDirs.cpp +++ b/src/libxrpl/ledger/BookDirs.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace xrpl { diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index f51fb97993..ef6a66744d 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -4,7 +4,10 @@ #include #include #include +#include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/Transactor.cpp b/src/libxrpl/tx/Transactor.cpp index 1c937f9380..6e334b5563 100644 --- a/src/libxrpl/tx/Transactor.cpp +++ b/src/libxrpl/tx/Transactor.cpp @@ -3,7 +3,10 @@ #include #include #include +#include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/invariants/InvariantCheck.cpp b/src/libxrpl/tx/invariants/InvariantCheck.cpp index 00580b2548..16108472aa 100644 --- a/src/libxrpl/tx/invariants/InvariantCheck.cpp +++ b/src/libxrpl/tx/invariants/InvariantCheck.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/invariants/LoanInvariant.cpp b/src/libxrpl/tx/invariants/LoanInvariant.cpp index 01c4da46ac..0df7e409d1 100644 --- a/src/libxrpl/tx/invariants/LoanInvariant.cpp +++ b/src/libxrpl/tx/invariants/LoanInvariant.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/invariants/VaultInvariant.cpp b/src/libxrpl/tx/invariants/VaultInvariant.cpp index e955e00b50..f0dd82c2f8 100644 --- a/src/libxrpl/tx/invariants/VaultInvariant.cpp +++ b/src/libxrpl/tx/invariants/VaultInvariant.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/paths/BookTip.cpp b/src/libxrpl/tx/paths/BookTip.cpp index f00da6d7c7..5611a081c3 100644 --- a/src/libxrpl/tx/paths/BookTip.cpp +++ b/src/libxrpl/tx/paths/BookTip.cpp @@ -1,3 +1,5 @@ +#include +#include #include namespace xrpl { diff --git a/src/libxrpl/tx/paths/OfferStream.cpp b/src/libxrpl/tx/paths/OfferStream.cpp index b406c27298..b7dc431b23 100644 --- a/src/libxrpl/tx/paths/OfferStream.cpp +++ b/src/libxrpl/tx/paths/OfferStream.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/account/AccountDelete.cpp b/src/libxrpl/tx/transactors/account/AccountDelete.cpp index 822b6121de..fed265c125 100644 --- a/src/libxrpl/tx/transactors/account/AccountDelete.cpp +++ b/src/libxrpl/tx/transactors/account/AccountDelete.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/account/AccountSet.cpp b/src/libxrpl/tx/transactors/account/AccountSet.cpp index a3afe2092c..33759c6ec4 100644 --- a/src/libxrpl/tx/transactors/account/AccountSet.cpp +++ b/src/libxrpl/tx/transactors/account/AccountSet.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/account/SignerListSet.cpp b/src/libxrpl/tx/transactors/account/SignerListSet.cpp index 399e832740..fe9e80d7e0 100644 --- a/src/libxrpl/tx/transactors/account/SignerListSet.cpp +++ b/src/libxrpl/tx/transactors/account/SignerListSet.cpp @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp index 2e274f138d..9ac755cf4d 100644 --- a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp +++ b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp @@ -5,7 +5,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/check/CheckCancel.cpp b/src/libxrpl/tx/transactors/check/CheckCancel.cpp index d2a77698e0..2d08b2f1b0 100644 --- a/src/libxrpl/tx/transactors/check/CheckCancel.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCancel.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/check/CheckCash.cpp b/src/libxrpl/tx/transactors/check/CheckCash.cpp index 2edd3c3a9c..7fa53c7352 100644 --- a/src/libxrpl/tx/transactors/check/CheckCash.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCash.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/check/CheckCreate.cpp b/src/libxrpl/tx/transactors/check/CheckCreate.cpp index 43e000ad5b..50554a1beb 100644 --- a/src/libxrpl/tx/transactors/check/CheckCreate.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCreate.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp index 26ecf311fe..c4842b54e4 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp index af5c786c59..f8f0f01b63 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp @@ -1,7 +1,8 @@ #include #include -#include +#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp index 2a9aafc6be..9fb17c4d1f 100644 --- a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp +++ b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/dex/AMMCreate.cpp b/src/libxrpl/tx/transactors/dex/AMMCreate.cpp index 86128ed1cd..dd717948b3 100644 --- a/src/libxrpl/tx/transactors/dex/AMMCreate.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMCreate.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp b/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp index 9b78b9e2bf..cae83ccef1 100644 --- a/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/dex/OfferCancel.cpp b/src/libxrpl/tx/transactors/dex/OfferCancel.cpp index 58f9525f61..9d60347778 100644 --- a/src/libxrpl/tx/transactors/dex/OfferCancel.cpp +++ b/src/libxrpl/tx/transactors/dex/OfferCancel.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/src/libxrpl/tx/transactors/dex/OfferCreate.cpp b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp index 90c00c6280..d52fa94877 100644 --- a/src/libxrpl/tx/transactors/dex/OfferCreate.cpp +++ b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/did/DIDDelete.cpp b/src/libxrpl/tx/transactors/did/DIDDelete.cpp index e09fdd3510..0d5b63635f 100644 --- a/src/libxrpl/tx/transactors/did/DIDDelete.cpp +++ b/src/libxrpl/tx/transactors/did/DIDDelete.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/src/libxrpl/tx/transactors/did/DIDSet.cpp b/src/libxrpl/tx/transactors/did/DIDSet.cpp index 32edbce82e..cd5c9bbc96 100644 --- a/src/libxrpl/tx/transactors/did/DIDSet.cpp +++ b/src/libxrpl/tx/transactors/did/DIDSet.cpp @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp index 61e27a7c38..1250d950cd 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp @@ -1,8 +1,12 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp index adeee09390..8b823de160 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp @@ -3,9 +3,14 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp index e85b00e606..8a05b2b160 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp @@ -6,8 +6,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h b/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h index 2aa6ae6db5..5fdc43c359 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h +++ b/src/libxrpl/tx/transactors/escrow/EscrowHelpers.h @@ -3,9 +3,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include namespace xrpl { diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp index 4c55a7d33a..24aa3f8bf2 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp @@ -1,5 +1,6 @@ #include // +#include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp index 83f7d2d1c6..4630e6a360 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverDeposit.cpp @@ -1,5 +1,6 @@ #include // +#include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp index ca64c6bb56..6946992376 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp @@ -1,6 +1,8 @@ #include // +#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp index 85026654da..a755db7942 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp @@ -1,5 +1,7 @@ #include // +#include +#include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp index 2632b55812..f8813ddbef 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp @@ -1,5 +1,7 @@ #include // +#include +#include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp index e7d219d6c8..39b28f5110 100644 --- a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp @@ -1,5 +1,6 @@ #include // +#include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanManage.cpp b/src/libxrpl/tx/transactors/lending/LoanManage.cpp index 2dacb453b5..d507ba5499 100644 --- a/src/libxrpl/tx/transactors/lending/LoanManage.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanManage.cpp @@ -1,5 +1,6 @@ #include // +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanPay.cpp b/src/libxrpl/tx/transactors/lending/LoanPay.cpp index 3543b7607f..8739cb645a 100644 --- a/src/libxrpl/tx/transactors/lending/LoanPay.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanPay.cpp @@ -1,6 +1,7 @@ #include // #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index 7212f079ce..f046a24961 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -1,5 +1,7 @@ #include // +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp index 3022188ccf..15a745b8dd 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp index 40b7171015..f7c12b5488 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp @@ -1,6 +1,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/oracle/OracleDelete.cpp b/src/libxrpl/tx/transactors/oracle/OracleDelete.cpp index e55d96e246..bde403f821 100644 --- a/src/libxrpl/tx/transactors/oracle/OracleDelete.cpp +++ b/src/libxrpl/tx/transactors/oracle/OracleDelete.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/oracle/OracleSet.cpp b/src/libxrpl/tx/transactors/oracle/OracleSet.cpp index 6b21df4d2a..061dd16b0c 100644 --- a/src/libxrpl/tx/transactors/oracle/OracleSet.cpp +++ b/src/libxrpl/tx/transactors/oracle/OracleSet.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp index 55a27e28ed..60b8dcd823 100644 --- a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp +++ b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment/Payment.cpp b/src/libxrpl/tx/transactors/payment/Payment.cpp index 6fc6d995fa..38765016b5 100644 --- a/src/libxrpl/tx/transactors/payment/Payment.cpp +++ b/src/libxrpl/tx/transactors/payment/Payment.cpp @@ -1,8 +1,12 @@ #include #include +#include #include +#include +#include #include #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp index 113dd89221..3f7e1e1814 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp index 75b68768ed..176b920e6b 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PaymentChannelHelpers.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp index 2c7e934fc0..565631b3fd 100644 --- a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp +++ b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainDelete.cpp @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp index f4d4f6a805..e8df51c9d9 100644 --- a/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp +++ b/src/libxrpl/tx/transactors/permissioned_domain/PermissionedDomainSet.cpp @@ -1,7 +1,9 @@ #include // #include +#include #include +#include #include #include diff --git a/src/libxrpl/tx/transactors/system/TicketCreate.cpp b/src/libxrpl/tx/transactors/system/TicketCreate.cpp index 8a9a5cbc93..a064c158d1 100644 --- a/src/libxrpl/tx/transactors/system/TicketCreate.cpp +++ b/src/libxrpl/tx/transactors/system/TicketCreate.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/token/Clawback.cpp b/src/libxrpl/tx/transactors/token/Clawback.cpp index a3ac810e90..e8ba3cc0c5 100644 --- a/src/libxrpl/tx/transactors/token/Clawback.cpp +++ b/src/libxrpl/tx/transactors/token/Clawback.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp b/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp index 208936a5e6..77551b372b 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp index 9f9362da4e..58accf0271 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceDestroy.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceDestroy.cpp index 1df4da47ab..8ec1f37886 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceDestroy.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceDestroy.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/token/TrustSet.cpp b/src/libxrpl/tx/transactors/token/TrustSet.cpp index c620592619..22588b977a 100644 --- a/src/libxrpl/tx/transactors/token/TrustSet.cpp +++ b/src/libxrpl/tx/transactors/token/TrustSet.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultClawback.cpp b/src/libxrpl/tx/transactors/vault/VaultClawback.cpp index ed47dfb63d..a650aed310 100644 --- a/src/libxrpl/tx/transactors/vault/VaultClawback.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultClawback.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp index a5b039f06b..0fc074bae2 100644 --- a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp index ad39ed9cf2..1e2e46e165 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp index bceaa354a1..04b249d211 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index 2507563bde..e4c671b462 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index f84253588c..a0a38b9791 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/src/test/app/AccountSet_test.cpp b/src/test/app/AccountSet_test.cpp index cfd7262a50..7af917a0b9 100644 --- a/src/test/app/AccountSet_test.cpp +++ b/src/test/app/AccountSet_test.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include diff --git a/src/test/app/Check_test.cpp b/src/test/app/Check_test.cpp index f8bb0ddcf2..671f8aab1a 100644 --- a/src/test/app/Check_test.cpp +++ b/src/test/app/Check_test.cpp @@ -1,5 +1,6 @@ #include +#include #include #include diff --git a/src/test/app/FeeVote_test.cpp b/src/test/app/FeeVote_test.cpp index f4b8c1874c..f0599b8771 100644 --- a/src/test/app/FeeVote_test.cpp +++ b/src/test/app/FeeVote_test.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index 692d9d2b50..1e9514f756 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index e17ef1fd55..8372bb340b 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include #include #include diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index e62f7fee50..27a8d3b2e0 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -9,8 +9,9 @@ #include #include #include +#include #include -#include +#include #include #include #include diff --git a/src/test/consensus/NegativeUNL_test.cpp b/src/test/consensus/NegativeUNL_test.cpp index 23f7610300..46c6936809 100644 --- a/src/test/consensus/NegativeUNL_test.cpp +++ b/src/test/consensus/NegativeUNL_test.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include namespace xrpl { diff --git a/src/test/jtx/PathSet.h b/src/test/jtx/PathSet.h index a363f9dff9..c522ed635e 100644 --- a/src/test/jtx/PathSet.h +++ b/src/test/jtx/PathSet.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace xrpl { diff --git a/src/test/jtx/impl/TestHelpers.cpp b/src/test/jtx/impl/TestHelpers.cpp index 5e7a31adcd..e10a0c46d0 100644 --- a/src/test/jtx/impl/TestHelpers.cpp +++ b/src/test/jtx/impl/TestHelpers.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace xrpl { diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index b6b08734c7..a6283bb6f9 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -1,5 +1,6 @@ #include +#include #include #include diff --git a/src/test/jtx/impl/owners.cpp b/src/test/jtx/impl/owners.cpp index 53f2302143..855c5b04ff 100644 --- a/src/test/jtx/impl/owners.cpp +++ b/src/test/jtx/impl/owners.cpp @@ -1,5 +1,7 @@ #include +#include + namespace xrpl { namespace detail { diff --git a/src/test/jtx/owners.h b/src/test/jtx/owners.h index 785a9347dd..3f54e0c55f 100644 --- a/src/test/jtx/owners.h +++ b/src/test/jtx/owners.h @@ -2,7 +2,7 @@ #include -#include +#include #include #include diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index ec76b67e9c..18649a20a8 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/ledger/PaymentSandbox_test.cpp b/src/test/ledger/PaymentSandbox_test.cpp index 2a0d74e3d9..a5023aa328 100644 --- a/src/test/ledger/PaymentSandbox_test.cpp +++ b/src/test/ledger/PaymentSandbox_test.cpp @@ -2,7 +2,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/test/ledger/View_test.cpp b/src/test/ledger/View_test.cpp index bae29445c2..f57cb609cc 100644 --- a/src/test/ledger/View_test.cpp +++ b/src/test/ledger/View_test.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include diff --git a/src/test/rpc/Book_test.cpp b/src/test/rpc/Book_test.cpp index 7ebe6e97ae..8136af310a 100644 --- a/src/test/rpc/Book_test.cpp +++ b/src/test/rpc/Book_test.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index c0211059a1..ff8e7e55e9 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index d709981c46..aabb53230f 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -43,11 +43,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include #include #include #include diff --git a/src/xrpld/app/paths/AMMOffer.h b/src/xrpld/app/paths/AMMOffer.h index ebaa7311c0..aa6132dfce 100644 --- a/src/xrpld/app/paths/AMMOffer.h +++ b/src/xrpld/app/paths/AMMOffer.h @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/src/xrpld/app/paths/TrustLine.cpp b/src/xrpld/app/paths/TrustLine.cpp index 6c54aa52d7..963e1402be 100644 --- a/src/xrpld/app/paths/TrustLine.cpp +++ b/src/xrpld/app/paths/TrustLine.cpp @@ -1,5 +1,6 @@ #include +#include #include #include diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index ae0c371e3e..e0053956a8 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 142f07bf73..0c8693eef4 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index e37a184e07..620d901f22 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/AccountChannels.cpp b/src/xrpld/rpc/handlers/AccountChannels.cpp index d2c3d4546d..c418386a71 100644 --- a/src/xrpld/rpc/handlers/AccountChannels.cpp +++ b/src/xrpld/rpc/handlers/AccountChannels.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp index f144c934ec..15a6786e22 100644 --- a/src/xrpld/rpc/handlers/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/AccountInfo.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/AccountLines.cpp b/src/xrpld/rpc/handlers/AccountLines.cpp index 952141fb8d..b3b93c0eb1 100644 --- a/src/xrpld/rpc/handlers/AccountLines.cpp +++ b/src/xrpld/rpc/handlers/AccountLines.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/AccountOffers.cpp b/src/xrpld/rpc/handlers/AccountOffers.cpp index 842cac71eb..86ab140b03 100644 --- a/src/xrpld/rpc/handlers/AccountOffers.cpp +++ b/src/xrpld/rpc/handlers/AccountOffers.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/GatewayBalances.cpp b/src/xrpld/rpc/handlers/GatewayBalances.cpp index 60e031c812..f7acbc77e6 100644 --- a/src/xrpld/rpc/handlers/GatewayBalances.cpp +++ b/src/xrpld/rpc/handlers/GatewayBalances.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/NFTOffers.cpp b/src/xrpld/rpc/handlers/NFTOffers.cpp index 3af7c28f9e..5fe2e3bede 100644 --- a/src/xrpld/rpc/handlers/NFTOffers.cpp +++ b/src/xrpld/rpc/handlers/NFTOffers.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/NoRippleCheck.cpp b/src/xrpld/rpc/handlers/NoRippleCheck.cpp index f21a67a31d..73f51fca1a 100644 --- a/src/xrpld/rpc/handlers/NoRippleCheck.cpp +++ b/src/xrpld/rpc/handlers/NoRippleCheck.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include From df8bfbe5af6fbfe615c164429b7fac474bffb544 Mon Sep 17 00:00:00 2001 From: Vito <5780819+Tapanito@users.noreply.github.com> Date: Tue, 24 Mar 2026 12:37:06 +0100 Subject: [PATCH 16/16] fix: errors introduced post-merge --- src/test/app/Vault_test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index 64bbd2f88a..5b70f8a32f 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -5253,7 +5253,7 @@ class Vault_test : public beast::unit_test::suite testcase("VaultDelete data featureLendingProtocolV1_1 disabled"); env.disableFeature(featureLendingProtocolV1_1); delTx[sfMemoData] = strHex(std::string(maxDataPayloadLength, 'A')); - env(delTx, ter(temDISABLED), THISLINE); + env(delTx, ter(temDISABLED)); env.close(); env.enableFeature(featureLendingProtocolV1_1); } @@ -5262,7 +5262,7 @@ class Vault_test : public beast::unit_test::suite { testcase("VaultDelete data featureLendingProtocolV1_1 enabled data too large"); delTx[sfMemoData] = strHex(std::string(maxDataPayloadLength + 1, 'A')); - env(delTx, ter(temMALFORMED), THISLINE); + env(delTx, ter(temMALFORMED)); env.close(); } @@ -5270,7 +5270,7 @@ class Vault_test : public beast::unit_test::suite { testcase("VaultDelete data featureLendingProtocolV1_1 enabled data empty"); delTx[sfMemoData] = strHex(std::string(0, 'A')); - env(delTx, ter(temMALFORMED), THISLINE); + env(delTx, ter(temMALFORMED)); env.close(); } @@ -5278,12 +5278,12 @@ class Vault_test : public beast::unit_test::suite testcase("VaultDelete data featureLendingProtocolV1_1 enabled data valid"); PrettyAsset const xrpAsset = xrpIssue(); auto [tx, keylet] = vault.create({.owner = owner, .asset = xrpAsset}); - env(tx, ter(tesSUCCESS), THISLINE); + env(tx, ter(tesSUCCESS)); env.close(); // Recreate the transaction as the vault keylet changed auto delTx = vault.del({.owner = owner, .id = keylet.key}); delTx[sfMemoData] = strHex(std::string(maxDataPayloadLength, 'A')); - env(delTx, ter(tesSUCCESS), THISLINE); + env(delTx, ter(tesSUCCESS)); env.close(); } }