From 01c977bbfe4a36eb8ab65084fa5781d44d8bc6e5 Mon Sep 17 00:00:00 2001 From: Bart Date: Wed, 11 Mar 2026 13:43:58 +0100 Subject: [PATCH 01/60] ci: Fix rules used to determine when to upload Conan recipes (#6524) The refs as previously used pointed to the source branch, not the target branch. However, determining the target branch is different depending on the GitHub event. The pull request logic was incorrect and needed to be fixed, and the logic inside the workflow could be simplified. Both modifications have been made in this commit. --- .github/workflows/on-pr.yml | 2 +- .github/workflows/reusable-upload-recipe.yml | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index f54a95e223..66893d19d3 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -142,7 +142,7 @@ jobs: - should-run - build-test # Only run when committing to a PR that targets a release branch. - if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && startsWith(github.ref, 'refs/heads/release') }} + if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release') }} uses: ./.github/workflows/reusable-upload-recipe.yml secrets: remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }} diff --git a/.github/workflows/reusable-upload-recipe.yml b/.github/workflows/reusable-upload-recipe.yml index 6245fd06e1..178dd65b8e 100644 --- a/.github/workflows/reusable-upload-recipe.yml +++ b/.github/workflows/reusable-upload-recipe.yml @@ -69,22 +69,28 @@ jobs: conan export . --version=${{ steps.version.outputs.version }} conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }} + # When this workflow is triggered by a push event, it will always be when merging into the + # 'develop' branch, see on-trigger.yml. - name: Upload Conan recipe (develop) - if: ${{ github.ref == 'refs/heads/develop' }} + if: ${{ github.event_name == 'push' }} env: REMOTE_NAME: ${{ inputs.remote_name }} run: | conan export . --version=develop conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop + # When this workflow is triggered by a pull request event, it will always be when merging into + # one of the 'release' branches, see on-pr.yml. - name: Upload Conan recipe (rc) - if: ${{ startsWith(github.ref, 'refs/heads/release') }} + if: ${{ github.event_name == 'pull_request' }} env: REMOTE_NAME: ${{ inputs.remote_name }} run: | 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 + # release, see on-tag.yml. - name: Upload Conan recipe (release) if: ${{ github.event_name == 'tag' }} env: From bee2d112c6cc067e478d5f9dbc9748ad927382c4 Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Wed, 11 Mar 2026 13:18:18 +0000 Subject: [PATCH 02/60] ci: Fix how clang-tidy is run when .clang-tidy is changed (#6521) --- .clang-tidy | 2 +- .github/workflows/reusable-clang-tidy.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index dd95153ff5..fc067fde6f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -100,9 +100,9 @@ Checks: "-*, # bugprone-crtp-constructor-accessibility, # bugprone-move-forwarding-reference, # bugprone-switch-missing-default-case, +# bugprone-unused-raii, # bugprone-unused-return-value, # bugprone-use-after-move, -# bugprone-unused-raii, # # cppcoreguidelines-misleading-capture-default-by-value, # cppcoreguidelines-init-variables, diff --git a/.github/workflows/reusable-clang-tidy.yml b/.github/workflows/reusable-clang-tidy.yml index 5319c1627a..3d4bc3b2e3 100644 --- a/.github/workflows/reusable-clang-tidy.yml +++ b/.github/workflows/reusable-clang-tidy.yml @@ -51,5 +51,5 @@ jobs: if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }} uses: ./.github/workflows/reusable-clang-tidy-files.yml with: - files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '') || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }} + files: ${{ needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '' || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }} create_issue_on_failure: ${{ inputs.create_issue_on_failure }} From 7b3724b7a35596a39e6ee740f5a16bf08d5ed54f Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Wed, 11 Mar 2026 14:04:26 +0000 Subject: [PATCH 03/60] fix: Add missed clang-tidy `bugprone-inc-dec-conditions` check (#6526) --- src/xrpld/app/ledger/detail/LedgerReplayer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp index f649eb4d95..5aacf5b5a6 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp @@ -98,8 +98,12 @@ LedgerReplayer::createDeltas(std::shared_ptr task) { auto skipListItem = std::find(parameter.skipList_.begin(), parameter.skipList_.end(), parameter.startHash_); - if (skipListItem == parameter.skipList_.end() || - ++skipListItem == parameter.skipList_.end()) + auto const wasLast = skipListItem == parameter.skipList_.end(); + if (not wasLast) + ++skipListItem; + auto const isLast = skipListItem == parameter.skipList_.end(); + + if (wasLast || isLast) { JLOG(j_.error()) << "Task parameter error when creating deltas " << parameter.finishHash_; From c791cae1ec627bd34b29894eb9ea5ef78b36ce1e Mon Sep 17 00:00:00 2001 From: Sergey Kuznetsov Date: Wed, 11 Mar 2026 18:06:12 +0000 Subject: [PATCH 04/60] test: Fix flaky subscribe tests (#6510) Subscribe tests have a problem that there is no way to synchronize application running in background threads and test threads. Threads are communicating via websocket messages. When the code is compiled in debug mode with code coverage enabled it executes quite slow, so receiving websocket messages by the client in subscribe tests may time out. This change does 2 things to fix the problem: * Increases timeout for receiving a websocket message. * Decreases the number of tests running in parallel. While testing the fix for subscribe test another flaky test in ledger replay was found, which has also been addressed. --- .../workflows/reusable-build-test-config.yml | 2 ++ src/test/app/LedgerReplay_test.cpp | 24 ++++++++++++++++--- src/test/rpc/Subscribe_test.cpp | 16 ++++++++----- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 66f46709cd..83ece81919 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -230,6 +230,8 @@ jobs: BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} run: | set -o pipefail + # Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness + [ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$(( BUILD_NPROC - 2 )) ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log - name: Show test failure summary diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp index 5568a90d03..4428e82ea9 100644 --- a/src/test/app/LedgerReplay_test.cpp +++ b/src/test/app/LedgerReplay_test.cpp @@ -1128,9 +1128,27 @@ struct LedgerReplayer_test : public beast::unit_test::suite BEAST_EXPECT(net.client.waitAndCheckStatus( finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses)); - // sweep - net.client.replayer.sweep(); - BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0)); + // sweep() cleans up skipLists_ and deltas_ by removing entries whose + // weak_ptr can no longer be locked. Those weak_ptrs expire only when the + // last shared_ptr holder releases the sub-task. The sole owner is the + // LedgerReplayTask, but a JobQueue worker thread may still hold a + // temporary shared_ptr to a sub-task (from wptr.lock()) while executing + // the timer job that drove the task to completion. If sweep() runs before + // that thread unwinds, the weak_ptr is still lockable and the map entry + // is not removed. We retry until the worker thread finishes. + auto waitForSweep = [&net]() { + for (auto numAttempts = 0; numAttempts < 20; ++numAttempts) + { + net.client.replayer.sweep(); + if (net.client.countsAsExpected(0, 0, 0)) + { + return true; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + return false; + }; + BEAST_EXPECT(waitForSweep()); } void diff --git a/src/test/rpc/Subscribe_test.cpp b/src/test/rpc/Subscribe_test.cpp index 414bceefd7..9a24980d49 100644 --- a/src/test/rpc/Subscribe_test.cpp +++ b/src/test/rpc/Subscribe_test.cpp @@ -802,13 +802,17 @@ public: * return {true, true} if received numReplies replies and also * received a tx with the account_history_tx_first == true */ - auto getTxHash = [](WSClient& wsc, IdxHashVec& v, int numReplies) -> std::pair { + auto getTxHash = [](WSClient& wsc, + IdxHashVec& v, + int numReplies, + std::chrono::milliseconds timeout = + std::chrono::milliseconds{5000}) -> std::pair { bool first_flag = false; for (int i = 0; i < numReplies; ++i) { std::uint32_t idx{0}; - auto reply = wsc.getMsg(100ms); + auto reply = wsc.getMsg(timeout); if (reply) { auto r = *reply; @@ -982,7 +986,7 @@ public: BEAST_EXPECT(goodSubRPC(jv)); sendPayments(env, env.master, alice, 1, 1); - r = getTxHash(*wscTxHistory, vec, 1); + r = getTxHash(*wscTxHistory, vec, 1, 10ms); BEAST_EXPECT(!r.first); } { @@ -1001,7 +1005,7 @@ public: return; IdxHashVec genesisFullHistoryVec; BEAST_EXPECT(env.syncClose()); - if (!BEAST_EXPECT(!getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first)) + if (!BEAST_EXPECT(!getTxHash(*wscTxHistory, genesisFullHistoryVec, 1, 10ms).first)) return; /* @@ -1161,7 +1165,7 @@ public: { // take out existing txns from the stream IdxHashVec tempVec; - getTxHash(*ws, tempVec, 100); + getTxHash(*ws, tempVec, 100, 1000ms); } auto count = mixedPayments(); @@ -1195,7 +1199,7 @@ public: { // take out existing txns from the stream IdxHashVec tempVec; - getTxHash(*wscLong, tempVec, 100); + getTxHash(*wscLong, tempVec, 100, 1000ms); } // repeat the payments many rounds From ce9ccf844a23963d08fc55ccc8a1d4b32d9cf41b Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 11 Mar 2026 15:36:03 -0400 Subject: [PATCH 05/60] fix: Remove unneeded import, fix log (#6532) This change: * Removes an unneeded import in `DeleteAccount.cpp`. * Fixes a typo in a log statement in `SetAccount.cpp`. --- src/libxrpl/tx/transactors/account/DeleteAccount.cpp | 1 - src/libxrpl/tx/transactors/account/SetAccount.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp b/src/libxrpl/tx/transactors/account/DeleteAccount.cpp index a9f7dbe674..68c0d7f304 100644 --- a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp +++ b/src/libxrpl/tx/transactors/account/DeleteAccount.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/src/libxrpl/tx/transactors/account/SetAccount.cpp b/src/libxrpl/tx/transactors/account/SetAccount.cpp index 32eb2afbb8..032b4727ad 100644 --- a/src/libxrpl/tx/transactors/account/SetAccount.cpp +++ b/src/libxrpl/tx/transactors/account/SetAccount.cpp @@ -491,7 +491,7 @@ SetAccount::doApply() if (messageKey.empty()) { - JLOG(j_.debug()) << "set message key"; + JLOG(j_.debug()) << "clear message key"; sle->makeFieldAbsent(sfMessageKey); } else From 46d5c67a8d2315e44e93dcbaf5dd3402d22cba28 Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Wed, 11 Mar 2026 17:27:35 -0400 Subject: [PATCH 06/60] fix: Mark SAV and Lending transactions as `NotDelegable` (#6489) New transactions should be marked as `NotDelegable`, until the interactions with other transactions have been fully tested and validated. --- .../xrpl/protocol/detail/transactions.macro | 30 ++--- src/test/app/Delegate_test.cpp | 59 +++++++- src/test/app/Vault_test.cpp | 126 ------------------ 3 files changed, 67 insertions(+), 148 deletions(-) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 08832acde7..01f5b50fb6 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -830,7 +830,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet, # include #endif TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, - Delegation::delegable, + Delegation::notDelegable, featureSingleAssetVault, createPseudoAcct | createMPTIssuance | mustModifyVault, ({ @@ -848,7 +848,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, # include #endif TRANSACTION(ttVAULT_SET, 66, VaultSet, - Delegation::delegable, + Delegation::notDelegable, featureSingleAssetVault, mustModifyVault, ({ @@ -863,7 +863,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet, # include #endif TRANSACTION(ttVAULT_DELETE, 67, VaultDelete, - Delegation::delegable, + Delegation::notDelegable, featureSingleAssetVault, mustDeleteAcct | destroyMPTIssuance | mustModifyVault, ({ @@ -875,7 +875,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete, # include #endif TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit, - Delegation::delegable, + Delegation::notDelegable, featureSingleAssetVault, mayAuthorizeMPT | mustModifyVault, ({ @@ -888,7 +888,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit, # include #endif TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, - Delegation::delegable, + Delegation::notDelegable, featureSingleAssetVault, mayDeleteMPT | mayAuthorizeMPT | mustModifyVault, ({ @@ -903,7 +903,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, # include #endif TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback, - Delegation::delegable, + Delegation::notDelegable, featureSingleAssetVault, mayDeleteMPT | mustModifyVault, ({ @@ -932,7 +932,7 @@ TRANSACTION(ttBATCH, 71, Batch, # include #endif TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, createPseudoAcct | mayAuthorizeMPT, ({ {sfVaultID, soeREQUIRED}, @@ -949,7 +949,7 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet, # include #endif TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, mustDeleteAcct | mayAuthorizeMPT, ({ {sfLoanBrokerID, soeREQUIRED}, @@ -960,7 +960,7 @@ TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete, # include #endif TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, noPriv, ({ {sfLoanBrokerID, soeREQUIRED}, @@ -972,7 +972,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit, # include #endif TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, mayAuthorizeMPT, ({ {sfLoanBrokerID, soeREQUIRED}, @@ -987,7 +987,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw, # include #endif TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, noPriv, ({ {sfLoanBrokerID, soeOPTIONAL}, @@ -999,7 +999,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback, # include #endif TRANSACTION(ttLOAN_SET, 80, LoanSet, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, mayAuthorizeMPT | mustModifyVault, ({ {sfLoanBrokerID, soeREQUIRED}, @@ -1026,7 +1026,7 @@ TRANSACTION(ttLOAN_SET, 80, LoanSet, # include #endif TRANSACTION(ttLOAN_DELETE, 81, LoanDelete, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, noPriv, ({ {sfLoanID, soeREQUIRED}, @@ -1037,7 +1037,7 @@ TRANSACTION(ttLOAN_DELETE, 81, LoanDelete, # include #endif TRANSACTION(ttLOAN_MANAGE, 82, LoanManage, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, // All of the LoanManage options will modify the vault, but the // transaction can succeed without options, essentially making it @@ -1051,7 +1051,7 @@ TRANSACTION(ttLOAN_MANAGE, 82, LoanManage, # include #endif TRANSACTION(ttLOAN_PAY, 84, LoanPay, - Delegation::delegable, + Delegation::notDelegable, featureLendingProtocol, mayAuthorizeMPT | mustModifyVault, ({ {sfLoanID, soeREQUIRED}, diff --git a/src/test/app/Delegate_test.cpp b/src/test/app/Delegate_test.cpp index 31a394eeeb..cbfa29c215 100644 --- a/src/test/app/Delegate_test.cpp +++ b/src/test/app/Delegate_test.cpp @@ -1614,13 +1614,7 @@ class Delegate_test : public beast::unit_test::suite {"CredentialDelete", featureCredentials}, {"NFTokenModify", featureDynamicNFT}, {"PermissionedDomainSet", featurePermissionedDomains}, - {"PermissionedDomainDelete", featurePermissionedDomains}, - {"VaultCreate", featureSingleAssetVault}, - {"VaultSet", featureSingleAssetVault}, - {"VaultDelete", featureSingleAssetVault}, - {"VaultDeposit", featureSingleAssetVault}, - {"VaultWithdraw", featureSingleAssetVault}, - {"VaultClawback", featureSingleAssetVault}}; + {"PermissionedDomainDelete", featurePermissionedDomains}}; // Can not delegate tx if any required feature disabled. { @@ -1660,6 +1654,56 @@ class Delegate_test : public beast::unit_test::suite } } + void + testTxDelegableCount() + { + testcase("Delegable Transactions Completeness"); + + std::size_t delegableCount = 0; + +#pragma push_macro("TRANSACTION") +#undef TRANSACTION + +#define TRANSACTION(tag, value, name, delegable, ...) \ + if (delegable == xrpl::delegable) \ + { \ + delegableCount++; \ + } + +#include + +#undef TRANSACTION +#pragma pop_macro("TRANSACTION") + + // ==================================================================== + // IMPORTANT NOTICE: + // + // If this test fails, it indicates that the 'Delegation::delegable' status + // in transactions.macro has been changed. Delegation allows accounts to act + // on behalf of others, significantly increasing the security surface. + // + // + // To ENSURE any added transaction is safe and compatible with delegation: + // + // 1. Verify that the transaction is intended to be delegable. + // 2. Every standard test case for that transaction MUST be + // duplicated and verified for a Delegated context. + // 3. Ensure that Fee, Reserve, and Signing are correctly handled. + // + // DO NOT modify expectedDelegableCount unless all scenarios, including + // edge cases, have been fully tested and verified. + // ==================================================================== + std::size_t const expectedDelegableCount = 75; + + BEAST_EXPECTS( + delegableCount == expectedDelegableCount, + "\n[SECURITY] New delegable transaction detected!" + "\n Expected: " + + std::to_string(expectedDelegableCount) + + "\n Actual: " + std::to_string(delegableCount) + + "\n Action: Verify security requirements to interact with Delegation feature"); + } + void run() override { @@ -1684,6 +1728,7 @@ class Delegate_test : public beast::unit_test::suite testMultiSignQuorumNotMet(); testPermissionValue(all); testTxRequireFeatures(all); + testTxDelegableCount(); } }; BEAST_DEFINE_TESTSUITE(Delegate, app, xrpl); diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index 7ae9faf18f..26ec59994d 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -4500,131 +4500,6 @@ class Vault_test : public beast::unit_test::suite } } - void - testDelegate() - { - using namespace test::jtx; - - Env env(*this, testable_amendments()); - Account alice{"alice"}; - Account bob{"bob"}; - Account carol{"carol"}; - - struct CaseArgs - { - PrettyAsset asset = xrpIssue(); - }; - - auto const xrpBalance = [this]( - Env const& env, Account const& account) -> std::optional { - auto sle = env.le(keylet::account(account.id())); - if (BEAST_EXPECT(sle != nullptr)) - return sle->getFieldAmount(sfBalance).xrp().drops(); - return std::nullopt; - }; - - auto testCase = [&, this](auto test, CaseArgs args = {}) { - Env env{*this, testable_amendments() | featureSingleAssetVault}; - - Vault vault{env}; - - // use different initial amount to distinguish the source balance - env.fund(XRP(10000), alice); - env.fund(XRP(20000), bob); - env.fund(XRP(30000), carol); - env.close(); - - env(delegate::set( - carol, - alice, - {"Payment", - "VaultCreate", - "VaultSet", - "VaultDelete", - "VaultDeposit", - "VaultWithdraw", - "VaultClawback"})); - - test(env, vault, args.asset); - }; - - testCase([&, this](Env& env, Vault& vault, PrettyAsset const& asset) { - testcase("delegated vault creation"); - auto startBalance = xrpBalance(env, carol); - if (!BEAST_EXPECT(startBalance.has_value())) - return; - - auto [tx, keylet] = vault.create({.owner = carol, .asset = asset}); - env(tx, delegate::as(alice)); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance); - }); - - testCase([&, this](Env& env, Vault& vault, PrettyAsset const& asset) { - testcase("delegated deposit and withdrawal"); - auto [tx, keylet] = vault.create({.owner = carol, .asset = asset}); - env(tx); - env.close(); - - auto const amount = 1513; - auto const baseFee = env.current()->fees().base; - - auto startBalance = xrpBalance(env, carol); - if (!BEAST_EXPECT(startBalance.has_value())) - return; - - tx = vault.deposit({.depositor = carol, .id = keylet.key, .amount = asset(amount)}); - env(tx, delegate::as(alice)); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount); - - tx = - vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(amount - 1)}); - env(tx, delegate::as(alice)); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - 1); - - tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(1)}); - env(tx); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee); - }); - - testCase([&, this](Env& env, Vault& vault, PrettyAsset const& asset) { - testcase("delegated withdrawal same as base fee and deletion"); - auto [tx, keylet] = vault.create({.owner = carol, .asset = asset}); - env(tx); - env.close(); - - auto const amount = 25537; - auto const baseFee = env.current()->fees().base; - - auto startBalance = xrpBalance(env, carol); - if (!BEAST_EXPECT(startBalance.has_value())) - return; - - tx = vault.deposit({.depositor = carol, .id = keylet.key, .amount = asset(amount)}); - env(tx); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount - baseFee); - - tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(baseFee)}); - env(tx, delegate::as(alice)); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount); - - tx = vault.withdraw( - {.depositor = carol, .id = keylet.key, .amount = asset(amount - baseFee)}); - env(tx, delegate::as(alice)); - env.close(); - BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee); - - tx = vault.del({.owner = carol, .id = keylet.key}); - env(tx, delegate::as(alice)); - env.close(); - }); - } - void testVaultClawbackBurnShares() { @@ -5374,7 +5249,6 @@ public: testFailedPseudoAccount(); testScaleIOU(); testRPC(); - testDelegate(); testVaultClawbackBurnShares(); testVaultClawbackAssets(); testAssetsMaximum(); From e460ea084029063a92183728c9fa047bd16677d9 Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Thu, 12 Mar 2026 05:39:40 +0000 Subject: [PATCH 07/60] ci: Move Type of Change from PR template to CONTRIBUTING (#6522) Now that prefixes in PR titles are being validated as part of CI, the "Type of Change" section in the PR template is no longer needed. The prefixes and descriptions in the `CONTRIBUTING.md` file have been updated to reflect the currently supported list. --- .github/pull_request_template.md | 16 -------------- CONTRIBUTING.md | 37 +++++++++++++++----------------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 3ab3a38807..f1f7aa18f7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -29,22 +29,6 @@ If a refactor, how is this better than the previous implementation? If there is a spec or design document for this feature, please link it here. --> -### Type of Change - - - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Refactor (non-breaking change that only restructures code) -- [ ] Performance (increase or change in throughput and/or latency) -- [ ] Tests (you added tests for code that already exists, or your new feature included in this PR) -- [ ] Documentation update -- [ ] Chore (no impact to binary, e.g. `.gitignore`, formatting, dropping support for older tooling) -- [ ] Release - ### API Impact Domain. app_.logs()); - if (rc.result() != tesSUCCESS) + if (!isTesSuccess(rc.result())) { JLOG(m_journal.warn()) << iIdentifier << " Failed with covering path " << transHuman(rc.result()); diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index b852ebd4d4..38d4488663 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -348,7 +348,7 @@ Pathfinder::getPathLiquidity( app_.logs(), &rcInput); // If we can't get even the minimum liquidity requested, we're done. - if (rc.result() != tesSUCCESS) + if (!isTesSuccess(rc.result())) return rc.result(); qualityOut = getRate(rc.actualAmountOut, rc.actualAmountIn); @@ -494,7 +494,7 @@ Pathfinder::rankPaths( uint64_t uQuality = 0; auto const resultCode = getPathLiquidity(currentPath, saMinDstAmount, liquidity, uQuality); - if (resultCode != tesSUCCESS) + if (!isTesSuccess(resultCode)) { JLOG(j_.debug()) << "findPaths: dropping : " << transToken(resultCode) << ": " << currentPath.getJson(JsonOptions::none); diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index 7fe55c3cad..37ca16c72d 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -811,7 +811,7 @@ BookStep::consumeOffer( { auto const dr = offer.send(sb, book_.in.account, offer.owner(), toSTAmount(ofrAmt.in, book_.in), j_); - if (dr != tesSUCCESS) + if (!isTesSuccess(dr)) Throw(dr); } @@ -820,7 +820,7 @@ BookStep::consumeOffer( { auto const cr = offer.send(sb, offer.owner(), book_.out.account, toSTAmount(ownerGives, book_.out), j_); - if (cr != tesSUCCESS) + if (!isTesSuccess(cr)) Throw(cr); } @@ -1336,7 +1336,7 @@ make_BookStepHelper(StrandContext const& ctx, Issue const& in, Issue const& out) ter = paymentStep->check(ctx); r = std::move(paymentStep); } - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return {ter, nullptr}; return {tesSUCCESS, std::move(r)}; diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 3297a9368a..dab16f010d 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -822,7 +822,7 @@ DirectStepI::check(StrandContext const& ctx) const if (!(ctx.isLast && ctx.isFirst)) { auto const ter = checkFreeze(ctx.view, src_, dst_, currency_); - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return ter; } @@ -833,7 +833,7 @@ DirectStepI::check(StrandContext const& ctx) const if (auto prevSrc = ctx.prevStep->directStepSrcAcct()) { auto const ter = checkNoRipple(ctx.view, *prevSrc, src_, dst_, currency_, j_); - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return ter; } } @@ -916,7 +916,7 @@ make_DirectStepI( ter = paymentStep->check(ctx); r = std::move(paymentStep); } - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return {ter, nullptr}; return {tesSUCCESS, std::move(r)}; diff --git a/src/xrpld/app/paths/detail/PaySteps.cpp b/src/xrpld/app/paths/detail/PaySteps.cpp index 7bbcb2a72c..e438d4442a 100644 --- a/src/xrpld/app/paths/detail/PaySteps.cpp +++ b/src/xrpld/app/paths/detail/PaySteps.cpp @@ -283,7 +283,7 @@ toStrand( JLOG(j.trace()) << "Inserting implied account"; auto msr = make_DirectStepI( ctx(), cur->getAccountID(), curIssue.account, curIssue.currency); - if (msr.first != tesSUCCESS) + if (!isTesSuccess(msr.first)) return {msr.first, Strand{}}; result.push_back(std::move(msr.second)); impliedPE.emplace( @@ -298,7 +298,7 @@ toStrand( JLOG(j.trace()) << "Inserting implied account before offer"; auto msr = make_DirectStepI( ctx(), cur->getAccountID(), curIssue.account, curIssue.currency); - if (msr.first != tesSUCCESS) + if (!isTesSuccess(msr.first)) return {msr.first, Strand{}}; result.push_back(std::move(msr.second)); impliedPE.emplace( @@ -318,7 +318,7 @@ toStrand( { // Last step. insert xrp endpoint step auto msr = make_XRPEndpointStep(ctx(), next->getAccountID()); - if (msr.first != tesSUCCESS) + if (!isTesSuccess(msr.first)) return {msr.first, Strand{}}; result.push_back(std::move(msr.second)); } @@ -328,7 +328,7 @@ toStrand( JLOG(j.trace()) << "Inserting implied account after offer"; auto msr = make_DirectStepI( ctx(), curIssue.account, next->getAccountID(), curIssue.currency); - if (msr.first != tesSUCCESS) + if (!isTesSuccess(msr.first)) return {msr.first, Strand{}}; result.push_back(std::move(msr.second)); } @@ -346,7 +346,7 @@ toStrand( } auto s = toStep(ctx(/*isLast*/ i == normPath.size() - 2), cur, next, curIssue); - if (s.first == tesSUCCESS) + if (isTesSuccess(s.first)) result.emplace_back(std::move(s.second)); else { @@ -457,7 +457,7 @@ toStrands( auto const ter = sp.first; auto& strand = sp.second; - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) { JLOG(j.trace()) << "failed to add default path"; if (isTemMalformed(ter) || paths.empty()) @@ -501,7 +501,7 @@ toStrands( auto ter = sp.first; auto& strand = sp.second; - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) { lastFailTer = ter; JLOG(j.trace()) << "failed to add path: ter: " << ter diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index 58390f498e..6eaa0d04c4 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -243,7 +243,7 @@ XRPEndpointStep::revImp( auto& sender = isLast_ ? xrpAccount() : acc_; auto& receiver = isLast_ ? acc_ : xrpAccount(); auto ter = accountSend(sb, sender, receiver, toSTAmount(result), j_); - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return {XRPAmount{beast::zero}, XRPAmount{beast::zero}}; cache_.emplace(result); @@ -266,7 +266,7 @@ XRPEndpointStep::fwdImp( auto& sender = isLast_ ? xrpAccount() : acc_; auto& receiver = isLast_ ? acc_ : xrpAccount(); auto ter = accountSend(sb, sender, receiver, toSTAmount(result), j_); - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return {XRPAmount{beast::zero}, XRPAmount{beast::zero}}; cache_.emplace(result); @@ -332,7 +332,7 @@ XRPEndpointStep::check(StrandContext const& ctx) const auto& src = isLast_ ? xrpAccount() : acc_; auto& dst = isLast_ ? acc_ : xrpAccount(); auto ter = checkFreeze(ctx.view, src, dst, xrpCurrency()); - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return ter; auto const issuesIndex = isLast_ ? 0 : 1; @@ -380,7 +380,7 @@ make_XRPEndpointStep(StrandContext const& ctx, AccountID const& acc) ter = paymentStep->check(ctx); r = std::move(paymentStep); } - if (ter != tesSUCCESS) + if (!isTesSuccess(ter)) return {ter, nullptr}; return {tesSUCCESS, std::move(r)}; diff --git a/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp b/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp index f818c72b59..ef8bc448ee 100644 --- a/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp +++ b/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp @@ -17,7 +17,7 @@ canHaveMPTokenIssuanceID( return false; // if the transaction failed nothing could have been delivered. - if (transactionMeta.getResultTER() != tesSUCCESS) + if (!isTesSuccess(transactionMeta.getResultTER())) return false; return true; From b92a9a3053437646ed80c6f279f4508df0bcff87 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 18 Mar 2026 10:47:59 -0400 Subject: [PATCH 44/60] fix: Make assorted NFT fixes (#6566) This change: * Removes a set of unnecessary brackets in the initialization of an `std::uint32_t`. * Fixes a couple of incorrect flags (same value, just wrong variables - so no amendment needed). --- include/xrpl/tx/transactors/nft/NFTokenUtils.h | 7 ++++--- src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp | 2 +- src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/xrpl/tx/transactors/nft/NFTokenUtils.h b/include/xrpl/tx/transactors/nft/NFTokenUtils.h index f33bd6e911..33aab068c6 100644 --- a/include/xrpl/tx/transactors/nft/NFTokenUtils.h +++ b/include/xrpl/tx/transactors/nft/NFTokenUtils.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -95,7 +96,7 @@ tokenOfferCreatePreflight( std::uint16_t nftFlags, Rules const& rules, std::optional const& owner = std::nullopt, - std::uint32_t txFlags = lsfSellNFToken); + std::uint32_t txFlags = tfSellNFToken); /** Preclaim checks shared by NFTokenCreateOffer and NFTokenMint */ TER @@ -109,7 +110,7 @@ tokenOfferCreatePreclaim( std::uint16_t xferFee, beast::Journal j, std::optional const& owner = std::nullopt, - std::uint32_t txFlags = lsfSellNFToken); + std::uint32_t txFlags = tfSellNFToken); /** doApply implementation shared by NFTokenCreateOffer and NFTokenMint */ TER @@ -123,7 +124,7 @@ tokenOfferCreateApply( uint256 const& nftokenID, XRPAmount const& priorBalance, beast::Journal j, - std::uint32_t txFlags = lsfSellNFToken); + std::uint32_t txFlags = tfSellNFToken); TER checkTrustlineAuthorized( diff --git a/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp b/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp index 847d15a3b7..eaca8b3380 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp @@ -42,7 +42,7 @@ NFTokenCreateOffer::preclaim(PreclaimContext const& ctx) return tecEXPIRED; uint256 const nftokenID = ctx.tx[sfNFTokenID]; - std::uint32_t const txFlags = {ctx.tx.getFlags()}; + std::uint32_t const txFlags = ctx.tx.getFlags(); if (!nft::findToken( ctx.view, ctx.tx[(txFlags & tfSellNFToken) ? sfAccount : sfOwner], nftokenID)) diff --git a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp index 9f550327e5..177092787c 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp @@ -619,8 +619,8 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer) auto const nftokenID = (*offer)[sfNFTokenID]; if (!view.dirRemove( - ((*offer)[sfFlags] & tfSellNFToken) ? keylet::nft_sells(nftokenID) - : keylet::nft_buys(nftokenID), + ((*offer)[sfFlags] & lsfSellNFToken) ? keylet::nft_sells(nftokenID) + : keylet::nft_buys(nftokenID), (*offer)[sfNFTokenOfferNode], offer->key(), false)) From 57e4cbbcd977c7fecb9df1b52a72b5a1d8ff4cf8 Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Wed, 18 Mar 2026 16:41:49 +0000 Subject: [PATCH 45/60] refactor: Add simple clang-tidy readability checks (#6556) This change enables the following clang-tidy checks: - readability-avoid-nested-conditional-operator, - readability-avoid-return-with-void-value, - readability-braces-around-statements, - readability-const-return-type, - readability-container-contains, - readability-container-size-empty, - readability-else-after-return, - readability-make-member-function-const, - readability-redundant-casting, - readability-redundant-inline-specifier, - readability-redundant-member-init, - readability-redundant-string-init, - readability-reference-to-constructed-temporary, - readability-static-definition --- .clang-tidy | 32 +- include/xrpl/protocol/Permissions.h | 2 +- include/xrpl/protocol/STObject.h | 2 +- include/xrpl/server/InfoSub.h | 2 +- include/xrpl/tx/invariants/InvariantCheck.h | 20 +- include/xrpl/tx/invariants/MPTInvariant.h | 2 +- include/xrpl/tx/invariants/NFTInvariant.h | 4 +- src/libxrpl/basics/BasicConfig.cpp | 6 +- src/libxrpl/basics/Log.cpp | 4 + src/libxrpl/basics/MallocTrim.cpp | 2 +- src/libxrpl/basics/Number.cpp | 12 +- src/libxrpl/basics/ResolverAsio.cpp | 2 +- src/libxrpl/basics/base64.cpp | 4 +- src/libxrpl/basics/make_SSLContext.cpp | 2 + src/libxrpl/beast/core/SemanticVersion.cpp | 42 ++- src/libxrpl/beast/net/IPEndpoint.cpp | 8 +- src/libxrpl/beast/utility/beast_Journal.cpp | 4 + .../beast/utility/beast_PropertyStream.cpp | 16 + src/libxrpl/core/detail/Workers.cpp | 8 +- src/libxrpl/crypto/RFC1751.cpp | 8 + src/libxrpl/json/Writer.cpp | 8 +- src/libxrpl/json/json_reader.cpp | 32 +- src/libxrpl/json/json_value.cpp | 23 +- src/libxrpl/json/json_valueiterator.cpp | 2 +- src/libxrpl/json/json_writer.cpp | 20 ++ src/libxrpl/ledger/ApplyStateTable.cpp | 6 +- src/libxrpl/ledger/BookListeners.cpp | 2 + src/libxrpl/ledger/CachedView.cpp | 6 + src/libxrpl/ledger/CredentialHelpers.cpp | 10 +- src/libxrpl/ledger/OpenView.cpp | 6 +- src/libxrpl/ledger/PaymentSandbox.cpp | 20 +- src/libxrpl/ledger/RawStateTable.cpp | 14 +- src/libxrpl/ledger/View.cpp | 176 +++++++---- .../nodestore/backend/MemoryFactory.cpp | 4 + src/libxrpl/nodestore/backend/NuDBFactory.cpp | 4 + .../nodestore/backend/RocksDBFactory.cpp | 10 + src/libxrpl/protocol/Feature.cpp | 12 +- src/libxrpl/protocol/Indexes.cpp | 2 +- src/libxrpl/protocol/Issue.cpp | 6 + src/libxrpl/protocol/NFTokenID.cpp | 2 +- src/libxrpl/protocol/Permissions.cpp | 6 +- src/libxrpl/protocol/PublicKey.cpp | 4 +- src/libxrpl/protocol/Rules.cpp | 4 +- src/libxrpl/protocol/STAccount.cpp | 2 +- src/libxrpl/protocol/STAmount.cpp | 40 ++- src/libxrpl/protocol/STLedgerEntry.cpp | 4 + src/libxrpl/protocol/STNumber.cpp | 4 + src/libxrpl/protocol/STObject.cpp | 12 +- src/libxrpl/protocol/STParsedJSON.cpp | 4 + src/libxrpl/protocol/STTx.cpp | 10 +- src/libxrpl/protocol/STVar.cpp | 8 + src/libxrpl/protocol/STVector256.cpp | 2 + src/libxrpl/protocol/Serializer.cpp | 8 +- src/libxrpl/protocol/tokens.cpp | 2 +- src/libxrpl/rdb/SociDB.cpp | 12 + src/libxrpl/server/InfoSub.cpp | 10 +- src/libxrpl/server/LoadFeeTrack.cpp | 10 +- src/libxrpl/server/Port.cpp | 4 +- src/libxrpl/shamap/SHAMap.cpp | 8 + src/libxrpl/shamap/SHAMapDelta.cpp | 24 +- src/libxrpl/shamap/SHAMapInnerNode.cpp | 10 +- src/libxrpl/shamap/SHAMapLeafNode.cpp | 8 + src/libxrpl/shamap/SHAMapNodeID.cpp | 4 + src/libxrpl/shamap/SHAMapSync.cpp | 8 +- src/libxrpl/tx/Transactor.cpp | 8 + src/libxrpl/tx/apply.cpp | 8 + src/libxrpl/tx/applySteps.cpp | 2 + src/libxrpl/tx/invariants/AMMInvariant.cpp | 4 + src/libxrpl/tx/invariants/FreezeInvariant.cpp | 4 + src/libxrpl/tx/invariants/InvariantCheck.cpp | 26 +- src/libxrpl/tx/invariants/MPTInvariant.cpp | 17 +- src/libxrpl/tx/invariants/NFTInvariant.cpp | 4 +- .../invariants/PermissionedDEXInvariant.cpp | 4 + .../PermissionedDomainInvariant.cpp | 5 +- src/libxrpl/tx/invariants/VaultInvariant.cpp | 4 +- src/libxrpl/tx/paths/Flow.cpp | 4 + src/libxrpl/tx/paths/OfferStream.cpp | 2 + .../tx/transactors/account/DeleteAccount.cpp | 2 + .../tx/transactors/account/SetAccount.cpp | 22 +- .../tx/transactors/account/SetSignerList.cpp | 2 +- .../tx/transactors/bridge/XChainBridge.cpp | 38 +++ .../tx/transactors/check/CashCheck.cpp | 2 + .../tx/transactors/delegate/DelegateSet.cpp | 2 + src/libxrpl/tx/transactors/dex/AMMBid.cpp | 35 ++- .../tx/transactors/dex/AMMClawback.cpp | 6 + src/libxrpl/tx/transactors/dex/AMMCreate.cpp | 19 +- src/libxrpl/tx/transactors/dex/AMMDeposit.cpp | 44 ++- src/libxrpl/tx/transactors/dex/AMMHelpers.cpp | 68 ++--- src/libxrpl/tx/transactors/dex/AMMUtils.cpp | 32 +- src/libxrpl/tx/transactors/dex/AMMVote.cpp | 24 +- .../tx/transactors/dex/AMMWithdraw.cpp | 28 +- .../tx/transactors/dex/CreateOffer.cpp | 14 + .../tx/transactors/escrow/EscrowCancel.cpp | 2 + .../tx/transactors/escrow/EscrowCreate.cpp | 2 + .../tx/transactors/escrow/EscrowFinish.cpp | 10 + .../tx/transactors/lending/LendingHelpers.cpp | 78 +++-- .../lending/LoanBrokerCoverClawback.cpp | 6 +- .../tx/transactors/lending/LoanPay.cpp | 14 + .../tx/transactors/lending/LoanSet.cpp | 36 ++- .../tx/transactors/nft/NFTokenAcceptOffer.cpp | 2 + .../tx/transactors/nft/NFTokenMint.cpp | 21 +- .../tx/transactors/nft/NFTokenModify.cpp | 2 +- .../tx/transactors/nft/NFTokenUtils.cpp | 30 ++ .../tx/transactors/oracle/DeleteOracle.cpp | 9 +- .../tx/transactors/oracle/SetOracle.cpp | 10 + .../tx/transactors/payment/Payment.cpp | 30 +- .../payment_channel/PayChanClaim.cpp | 2 + .../payment_channel/PayChanFund.cpp | 2 + src/libxrpl/tx/transactors/system/Batch.cpp | 4 + src/libxrpl/tx/transactors/system/Change.cpp | 4 + src/libxrpl/tx/transactors/token/Clawback.cpp | 6 +- .../token/MPTokenIssuanceCreate.cpp | 2 +- .../transactors/token/MPTokenIssuanceSet.cpp | 26 +- src/libxrpl/tx/transactors/token/SetTrust.cpp | 21 +- .../tx/transactors/vault/VaultClawback.cpp | 4 +- .../tx/transactors/vault/VaultCreate.cpp | 12 +- .../tx/transactors/vault/VaultDeposit.cpp | 6 +- .../tx/transactors/vault/VaultWithdraw.cpp | 2 + src/test/app/AMMCalc_test.cpp | 14 +- src/test/app/AMMClawback_test.cpp | 280 ++++++++++++++++++ src/test/app/AMMExtended_test.cpp | 6 + src/test/app/AMM_test.cpp | 154 +++++++++- src/test/app/AccountSet_test.cpp | 4 + src/test/app/AmendmentTable_test.cpp | 16 +- src/test/app/Check_test.cpp | 46 +-- src/test/app/DNS_test.cpp | 4 +- src/test/app/DepositAuth_test.cpp | 2 + src/test/app/Discrepancy_test.cpp | 10 + src/test/app/EscrowToken_test.cpp | 4 + src/test/app/Flow_test.cpp | 8 + src/test/app/HashRouter_test.cpp | 2 +- src/test/app/Invariants_test.cpp | 53 ++-- src/test/app/LPTokenTransfer_test.cpp | 4 + src/test/app/LedgerLoad_test.cpp | 12 +- src/test/app/LedgerReplay_test.cpp | 10 +- src/test/app/LoanBroker_test.cpp | 28 +- src/test/app/Loan_test.cpp | 120 +++++--- src/test/app/MPToken_test.cpp | 6 + src/test/app/NFTokenBurn_test.cpp | 18 +- src/test/app/NFTokenDir_test.cpp | 4 + src/test/app/NFToken_test.cpp | 18 ++ src/test/app/Offer_test.cpp | 20 +- src/test/app/OversizeMeta_test.cpp | 2 + src/test/app/Path_test.cpp | 2 +- src/test/app/PayChan_test.cpp | 4 + src/test/app/PayStrand_test.cpp | 16 + src/test/app/PermissionedDomains_test.cpp | 10 +- src/test/app/RCLValidations_test.cpp | 4 + src/test/app/ReducedOffer_test.cpp | 2 + src/test/app/SHAMapStore_test.cpp | 4 +- src/test/app/SetTrust_test.cpp | 6 + src/test/app/TheoreticalQuality_test.cpp | 7 +- src/test/app/Ticket_test.cpp | 4 + src/test/app/TrustAndBalance_test.cpp | 4 + src/test/app/TxQ_test.cpp | 4 + src/test/app/ValidatorList_test.cpp | 67 ++++- src/test/app/ValidatorSite_test.cpp | 4 + src/test/app/Vault_test.cpp | 33 ++- src/test/app/XChain_test.cpp | 33 ++- src/test/basics/Buffer_test.cpp | 6 +- src/test/basics/IntrusiveShared_test.cpp | 4 +- src/test/basics/Number_test.cpp | 16 + src/test/basics/PerfLog_test.cpp | 11 +- src/test/basics/XRPAmount_test.cpp | 6 + src/test/beast/LexicalCast_test.cpp | 2 +- src/test/conditions/PreimageSha256_test.cpp | 2 +- src/test/consensus/Consensus_test.cpp | 40 +-- src/test/consensus/LedgerTiming_test.cpp | 6 + src/test/consensus/LedgerTrie_test.cpp | 6 +- src/test/consensus/NegativeUNL_test.cpp | 24 +- src/test/consensus/Validations_test.cpp | 4 + src/test/core/ClosureCounter_test.cpp | 2 +- src/test/core/Config_test.cpp | 26 +- src/test/csf/BasicNetwork_test.cpp | 4 + src/test/csf/impl/ledgers.cpp | 6 + src/test/jtx/Env_test.cpp | 4 +- src/test/jtx/impl/AMM.cpp | 58 +++- src/test/jtx/impl/AMMTest.cpp | 6 + src/test/jtx/impl/Env.cpp | 48 +-- src/test/jtx/impl/JSONRPCClient.cpp | 2 + src/test/jtx/impl/Oracle.cpp | 64 +++- src/test/jtx/impl/WSClient.cpp | 4 + src/test/jtx/impl/amount.cpp | 4 + src/test/jtx/impl/balance.cpp | 2 +- src/test/jtx/impl/directory.cpp | 4 + src/test/jtx/impl/fee.cpp | 4 + src/test/jtx/impl/flags.cpp | 12 + src/test/jtx/impl/mpt.cpp | 52 +++- src/test/jtx/impl/multisign.cpp | 8 + src/test/jtx/impl/sig.cpp | 4 + src/test/jtx/impl/vault.cpp | 2 +- src/test/jtx/impl/xchain_bridge.cpp | 4 + src/test/jtx/vault.h | 2 +- src/test/ledger/BookDirs_test.cpp | 2 + src/test/ledger/Directory_test.cpp | 10 + src/test/nodestore/Timing_test.cpp | 14 +- src/test/nodestore/import_test.cpp | 2 + src/test/overlay/compression_test.cpp | 2 +- src/test/overlay/reduce_relay_test.cpp | 31 +- src/test/overlay/short_read_test.cpp | 78 ++++- src/test/overlay/tx_reduce_relay_test.cpp | 11 +- src/test/peerfinder/Livecache_test.cpp | 2 +- src/test/peerfinder/PeerFinder_test.cpp | 2 +- src/test/protocol/STAccount_test.cpp | 4 +- src/test/protocol/STObject_test.cpp | 6 +- src/test/protocol/STParsedJSON_test.cpp | 4 +- src/test/protocol/SecretKey_test.cpp | 4 +- src/test/protocol/Seed_test.cpp | 8 +- src/test/resource/Logic_test.cpp | 20 ++ src/test/rpc/AMMInfo_test.cpp | 18 +- src/test/rpc/AccountObjects_test.cpp | 4 + src/test/rpc/AccountOffers_test.cpp | 2 +- src/test/rpc/AccountTx_test.cpp | 43 ++- src/test/rpc/DeliveredAmount_test.cpp | 22 ++ src/test/rpc/DepositAuthorized_test.cpp | 2 + src/test/rpc/Feature_test.cpp | 4 + src/test/rpc/KeyGeneration_test.cpp | 4 + src/test/rpc/LedgerData_test.cpp | 4 +- src/test/rpc/LedgerEntry_test.cpp | 22 +- src/test/rpc/LedgerRPC_test.cpp | 6 + src/test/rpc/NoRippleCheck_test.cpp | 2 + src/test/rpc/NoRipple_test.cpp | 4 + src/test/rpc/RPCOverload_test.cpp | 2 + src/test/rpc/ServerInfo_test.cpp | 2 +- src/test/rpc/Simulate_test.cpp | 2 +- src/test/rpc/Transaction_test.cpp | 8 + src/test/rpc/ValidatorRPC_test.cpp | 2 +- src/test/rpc/Version_test.cpp | 2 + src/test/server/ServerStatus_test.cpp | 5 +- src/test/server/Server_test.cpp | 4 + src/test/shamap/SHAMapSync_test.cpp | 2 +- src/test/shamap/SHAMap_test.cpp | 16 + src/test/unit_test/multi_runner.cpp | 6 +- src/tests/libxrpl/basics/Slice.cpp | 8 + src/xrpld/app/consensus/RCLConsensus.cpp | 14 +- src/xrpld/app/consensus/RCLCxPeerPos.cpp | 2 +- src/xrpld/app/consensus/RCLValidations.cpp | 4 + src/xrpld/app/ledger/AcceptedLedger.cpp | 2 + src/xrpld/app/ledger/Ledger.cpp | 22 +- src/xrpld/app/ledger/LedgerHistory.cpp | 4 + src/xrpld/app/ledger/OrderBookDBImpl.cpp | 30 ++ src/xrpld/app/ledger/detail/BuildLedger.cpp | 2 + src/xrpld/app/ledger/detail/InboundLedger.cpp | 40 ++- .../app/ledger/detail/InboundLedgers.cpp | 10 + .../app/ledger/detail/InboundTransactions.cpp | 12 +- src/xrpld/app/ledger/detail/LedgerCleaner.cpp | 2 + .../app/ledger/detail/LedgerDeltaAcquire.cpp | 16 +- src/xrpld/app/ledger/detail/LedgerMaster.cpp | 28 +- .../app/ledger/detail/LedgerReplayTask.cpp | 6 + .../app/ledger/detail/LedgerReplayer.cpp | 2 + src/xrpld/app/ledger/detail/LedgerToJson.cpp | 22 +- src/xrpld/app/ledger/detail/LocalTxs.cpp | 2 + .../app/ledger/detail/TransactionAcquire.cpp | 12 +- src/xrpld/app/main/Application.cpp | 14 +- src/xrpld/app/main/GRPCServer.cpp | 6 +- src/xrpld/app/main/LoadManager.cpp | 2 +- src/xrpld/app/main/Main.cpp | 114 +++---- src/xrpld/app/main/NodeIdentity.cpp | 4 +- src/xrpld/app/misc/FeeVoteImpl.cpp | 8 + src/xrpld/app/misc/NegativeUNLVote.cpp | 36 +-- src/xrpld/app/misc/NegativeUNLVote.h | 2 +- src/xrpld/app/misc/NetworkOPs.cpp | 86 +++++- src/xrpld/app/misc/SHAMapStoreImp.cpp | 16 +- src/xrpld/app/misc/detail/AccountTxPaging.cpp | 4 + src/xrpld/app/misc/detail/AmendmentTable.cpp | 38 +-- src/xrpld/app/misc/detail/TxQ.cpp | 36 ++- src/xrpld/app/misc/detail/ValidatorList.cpp | 164 +++++----- src/xrpld/app/misc/detail/ValidatorSite.cpp | 7 +- src/xrpld/app/misc/detail/WorkSSL.cpp | 10 +- .../app/misc/detail/setup_HashRouter.cpp | 4 + src/xrpld/app/paths/PathRequest.cpp | 14 +- src/xrpld/app/paths/PathRequests.cpp | 2 + src/xrpld/app/paths/Pathfinder.cpp | 20 +- src/xrpld/app/paths/RippleLineCache.cpp | 2 +- src/xrpld/app/paths/detail/AMMLiquidity.cpp | 33 ++- src/xrpld/app/paths/detail/BookStep.cpp | 91 +++--- src/xrpld/app/paths/detail/DirectStep.cpp | 34 +-- src/xrpld/app/paths/detail/PaySteps.cpp | 20 +- src/xrpld/app/rdb/backend/detail/Node.cpp | 46 ++- src/xrpld/core/detail/Config.cpp | 134 ++++++++- src/xrpld/overlay/detail/ConnectAttempt.cpp | 134 +++++++-- src/xrpld/overlay/detail/Handshake.cpp | 4 + src/xrpld/overlay/detail/Message.cpp | 10 +- src/xrpld/overlay/detail/OverlayImpl.cpp | 98 ++++-- src/xrpld/overlay/detail/OverlayImpl.h | 4 +- src/xrpld/overlay/detail/PeerImp.cpp | 255 ++++++++++++---- src/xrpld/overlay/detail/TrafficCount.cpp | 24 ++ src/xrpld/peerfinder/PeerfinderManager.h | 2 +- src/xrpld/peerfinder/detail/Bootcache.cpp | 8 +- .../peerfinder/detail/PeerfinderConfig.cpp | 11 +- .../peerfinder/detail/PeerfinderManager.cpp | 3 +- src/xrpld/perflog/detail/PerfLogImp.cpp | 10 +- src/xrpld/rpc/detail/Handler.cpp | 8 + src/xrpld/rpc/detail/RPCCall.cpp | 67 +++-- src/xrpld/rpc/detail/RPCHandler.cpp | 8 +- src/xrpld/rpc/detail/RPCHelpers.cpp | 18 +- src/xrpld/rpc/detail/RPCLedgerHelpers.cpp | 26 +- src/xrpld/rpc/detail/RPCSub.cpp | 15 +- src/xrpld/rpc/detail/Role.cpp | 6 +- src/xrpld/rpc/detail/ServerHandler.cpp | 50 +++- src/xrpld/rpc/detail/TransactionSign.cpp | 34 ++- src/xrpld/rpc/handlers/AMMInfo.cpp | 12 + src/xrpld/rpc/handlers/AccountInfo.cpp | 8 + src/xrpld/rpc/handlers/AccountLines.cpp | 4 + src/xrpld/rpc/handlers/AccountObjects.cpp | 10 +- src/xrpld/rpc/handlers/AccountTx.cpp | 20 +- src/xrpld/rpc/handlers/BlackList.cpp | 6 +- src/xrpld/rpc/handlers/BookOffers.cpp | 22 +- src/xrpld/rpc/handlers/Connect.cpp | 4 + src/xrpld/rpc/handlers/DepositAuthorized.cpp | 8 +- src/xrpld/rpc/handlers/Feature1.cpp | 4 + src/xrpld/rpc/handlers/GatewayBalances.cpp | 2 +- src/xrpld/rpc/handlers/LedgerData.cpp | 4 +- src/xrpld/rpc/handlers/LedgerEntry.cpp | 8 +- src/xrpld/rpc/handlers/LedgerHandler.cpp | 6 + src/xrpld/rpc/handlers/LogLevel.cpp | 4 + src/xrpld/rpc/handlers/NoRippleCheck.cpp | 4 + src/xrpld/rpc/handlers/PayChanClaim.cpp | 6 +- src/xrpld/rpc/handlers/Peers.cpp | 6 + src/xrpld/rpc/handlers/Ping.cpp | 2 +- src/xrpld/rpc/handlers/ServerDefinitions.cpp | 10 +- src/xrpld/rpc/handlers/Submit.cpp | 4 +- src/xrpld/rpc/handlers/Subscribe.cpp | 6 +- src/xrpld/rpc/handlers/TransactionEntry.cpp | 4 + src/xrpld/rpc/handlers/Tx.cpp | 8 +- src/xrpld/rpc/handlers/Unsubscribe.cpp | 12 +- src/xrpld/rpc/handlers/VaultInfo.cpp | 3 +- src/xrpld/rpc/handlers/WalletPropose.cpp | 8 + 328 files changed, 4415 insertions(+), 1176 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 642bcb8a96..d8a7cb1b6f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -98,12 +98,26 @@ Checks: "-*, performance-implicit-conversion-in-loop, performance-move-constructor-init, performance-trivially-destructible, + readability-avoid-nested-conditional-operator, + readability-avoid-return-with-void-value, + readability-braces-around-statements, + readability-const-return-type, + readability-container-contains, + readability-container-size-empty, readability-duplicate-include, + readability-else-after-return, readability-enum-initial-value, + readability-make-member-function-const, readability-misleading-indentation, readability-non-const-parameter, + readability-redundant-casting, readability-redundant-declaration, - readability-reference-to-constructed-temporary + readability-redundant-inline-specifier, + readability-redundant-member-init, + readability-redundant-string-init, + readability-reference-to-constructed-temporary, + readability-static-definition-in-anonymous-namespace, + readability-use-std-min-max " # --- # checks that have some issues that need to be resolved: @@ -113,27 +127,13 @@ Checks: "-*, # misc-include-cleaner, # misc-redundant-expression, # -# readability-avoid-nested-conditional-operator, -# readability-avoid-return-with-void-value, -# readability-braces-around-statements, -# readability-container-contains, -# readability-container-size-empty, # readability-convert-member-functions-to-static, -# readability-const-return-type, -# readability-else-after-return, # readability-implicit-bool-conversion, # readability-inconsistent-declaration-parameter-name, # readability-identifier-naming, -# readability-make-member-function-const, # readability-math-missing-parentheses, -# readability-redundant-inline-specifier, -# readability-redundant-member-init, -# readability-redundant-casting, -# readability-redundant-string-init, # readability-simplify-boolean-expr, -# readability-static-definition-in-anonymous-namespace, # readability-suspicious-call-argument, -# readability-use-std-min-max, # readability-static-accessed-through-instance, # # modernize-concat-nested-namespaces, @@ -157,7 +157,7 @@ Checks: "-*, # --- # CheckOptions: - # readability-braces-around-statements.ShortStatementLines: 2 + readability-braces-around-statements.ShortStatementLines: 2 # readability-identifier-naming.MacroDefinitionCase: UPPER_CASE # readability-identifier-naming.ClassCase: CamelCase # readability-identifier-naming.StructCase: CamelCase diff --git a/include/xrpl/protocol/Permissions.h b/include/xrpl/protocol/Permissions.h index e8800a41d2..65861addc7 100644 --- a/include/xrpl/protocol/Permissions.h +++ b/include/xrpl/protocol/Permissions.h @@ -65,7 +65,7 @@ public: std::optional getGranularTxType(GranularPermissionType const& gpType) const; - std::optional> const + std::optional> getTxFeature(TxType txType) const; bool diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 0eb76a80c1..ecfae0086b 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -401,7 +401,7 @@ public: getStyle(SField const& field) const; bool - hasMatchingEntry(STBase const&); + hasMatchingEntry(STBase const&) const; bool operator==(STObject const& o) const; diff --git a/include/xrpl/server/InfoSub.h b/include/xrpl/server/InfoSub.h index 97cdf1aa35..d45f4d7740 100644 --- a/include/xrpl/server/InfoSub.h +++ b/include/xrpl/server/InfoSub.h @@ -173,7 +173,7 @@ public: send(Json::Value const& jvObj, bool broadcast) = 0; std::uint64_t - getSeq(); + getSeq() const; void onSendEmpty(); diff --git a/include/xrpl/tx/invariants/InvariantCheck.h b/include/xrpl/tx/invariants/InvariantCheck.h index 64eff33ff7..e0ad65f14c 100644 --- a/include/xrpl/tx/invariants/InvariantCheck.h +++ b/include/xrpl/tx/invariants/InvariantCheck.h @@ -132,7 +132,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -152,7 +152,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -198,7 +198,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -215,7 +215,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -233,7 +233,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -252,7 +252,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -271,7 +271,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -287,7 +287,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -307,7 +307,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -328,7 +328,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** diff --git a/include/xrpl/tx/invariants/MPTInvariant.h b/include/xrpl/tx/invariants/MPTInvariant.h index b6533c263d..68f866d362 100644 --- a/include/xrpl/tx/invariants/MPTInvariant.h +++ b/include/xrpl/tx/invariants/MPTInvariant.h @@ -25,7 +25,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; } // namespace xrpl diff --git a/include/xrpl/tx/invariants/NFTInvariant.h b/include/xrpl/tx/invariants/NFTInvariant.h index 8a88ca1c63..5bb5f90437 100644 --- a/include/xrpl/tx/invariants/NFTInvariant.h +++ b/include/xrpl/tx/invariants/NFTInvariant.h @@ -36,7 +36,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; /** @@ -64,7 +64,7 @@ public: visitEntry(bool, std::shared_ptr const&, std::shared_ptr const&); bool - finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&); + finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const; }; } // namespace xrpl diff --git a/src/libxrpl/basics/BasicConfig.cpp b/src/libxrpl/basics/BasicConfig.cpp index 63d3a56c40..edc8bea7d9 100644 --- a/src/libxrpl/basics/BasicConfig.cpp +++ b/src/libxrpl/basics/BasicConfig.cpp @@ -55,7 +55,7 @@ Section::append(std::vector const& lines) val = ""; break; } - else if (val.at(comment - 1) == '\\') + if (val.at(comment - 1) == '\\') { // we have an escaped comment char. Erase the escape char // and keep looking @@ -83,9 +83,13 @@ Section::append(std::vector const& lines) boost::smatch match; if (boost::regex_match(line, match, re1)) + { set(match[1], match[2]); + } else + { values_.push_back(line); + } lines_.push_back(std::move(line)); } diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index 3e36b7d458..9cebd1f04a 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -417,9 +417,13 @@ public: swap(holder_, sink); if (holder_) + { sink_ = *holder_; + } else + { sink_ = beast::Journal::getNullSink(); + } return sink; } diff --git a/src/libxrpl/basics/MallocTrim.cpp b/src/libxrpl/basics/MallocTrim.cpp index 1b0932b39d..ed20ac6c94 100644 --- a/src/libxrpl/basics/MallocTrim.cpp +++ b/src/libxrpl/basics/MallocTrim.cpp @@ -51,7 +51,7 @@ parseStatmRSSkB(std::string const& statm) // /proc/self/statm format: size resident shared text lib data dt // We want the second field (resident) which is in pages std::istringstream iss(statm); - long size, resident; + long size = 0, resident = 0; if (!(iss >> size >> resident)) return -1; diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index 11d2368b03..b520261ffe 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -94,7 +94,7 @@ public: // This enables the client to round towards nearest, and on // tie, round towards even. int - round() noexcept; + round() const noexcept; // Modify the result to the correctly rounded value template @@ -114,7 +114,7 @@ public: // Modify the result to the correctly rounded value void - doRound(rep& drops, std::string location); + doRound(rep& drops, std::string location) const; private: void @@ -171,7 +171,7 @@ Number::Guard::pop() noexcept // 0 if Guard is exactly half // 1 if Guard is greater than half int -Number::Guard::round() noexcept +Number::Guard::round() const noexcept { auto mode = Number::getround(); @@ -282,7 +282,7 @@ Number::Guard::doRoundDown( // Modify the result to the correctly rounded value void -Number::Guard::doRound(rep& drops, std::string location) +Number::Guard::doRound(rep& drops, std::string location) const { auto r = round(); if (r == 1 || (r == 0 && (drops & 1) == 1)) @@ -911,9 +911,13 @@ to_string(Number const& amount) // Assemble the output: if (pre_from == pre_to) + { ret.append(1, '0'); + } else + { ret.append(pre_from, pre_to); + } if (post_to != post_from) { diff --git a/src/libxrpl/basics/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp index 225cbe2926..b746092645 100644 --- a/src/libxrpl/basics/ResolverAsio.cpp +++ b/src/libxrpl/basics/ResolverAsio.cpp @@ -374,7 +374,7 @@ public: JLOG(m_journal.debug()) << "Queued new job with " << names.size() << " tasks. " << m_work.size() << " jobs outstanding."; - if (m_work.size() > 0) + if (!m_work.empty()) { boost::asio::post( m_io_context, diff --git a/src/libxrpl/basics/base64.cpp b/src/libxrpl/basics/base64.cpp index 90bbc71359..31888ec99c 100644 --- a/src/libxrpl/basics/base64.cpp +++ b/src/libxrpl/basics/base64.cpp @@ -77,13 +77,13 @@ get_inverse() } /// Returns max chars needed to encode a base64 string -inline std::size_t constexpr encoded_size(std::size_t n) +std::size_t constexpr encoded_size(std::size_t n) { return 4 * ((n + 2) / 3); } /// Returns max bytes needed to decode a base64 string -inline std::size_t constexpr decoded_size(std::size_t n) +std::size_t constexpr decoded_size(std::size_t n) { return ((n / 4) * 3) + 2; } diff --git a/src/libxrpl/basics/make_SSLContext.cpp b/src/libxrpl/basics/make_SSLContext.cpp index 7fd6c5b97a..74aab709d8 100644 --- a/src/libxrpl/basics/make_SSLContext.cpp +++ b/src/libxrpl/basics/make_SSLContext.cpp @@ -272,9 +272,11 @@ initAuthenticated( if (!cert_set) { if (SSL_CTX_use_certificate(ssl, x) != 1) + { LogicError( "Problem retrieving SSL certificate from chain " "file."); + } cert_set = true; } diff --git a/src/libxrpl/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp index e8899e6854..34bb5e3df0 100644 --- a/src/libxrpl/beast/core/SemanticVersion.cpp +++ b/src/libxrpl/beast/core/SemanticVersion.cpp @@ -234,27 +234,43 @@ int compare(SemanticVersion const& lhs, SemanticVersion const& rhs) { if (lhs.majorVersion > rhs.majorVersion) + { return 1; - else if (lhs.majorVersion < rhs.majorVersion) + } + if (lhs.majorVersion < rhs.majorVersion) + { return -1; + } if (lhs.minorVersion > rhs.minorVersion) + { return 1; - else if (lhs.minorVersion < rhs.minorVersion) + } + if (lhs.minorVersion < rhs.minorVersion) + { return -1; + } if (lhs.patchVersion > rhs.patchVersion) + { return 1; - else if (lhs.patchVersion < rhs.patchVersion) + } + if (lhs.patchVersion < rhs.patchVersion) + { return -1; + } if (lhs.isPreRelease() || rhs.isPreRelease()) { // Pre-releases have a lower precedence if (lhs.isRelease() && rhs.isPreRelease()) + { return 1; - else if (lhs.isPreRelease() && rhs.isRelease()) + } + if (lhs.isPreRelease() && rhs.isRelease()) + { return -1; + } // Compare pre-release identifiers for (int i = 0; @@ -263,18 +279,26 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) { // A larger list of identifiers has a higher precedence if (i >= rhs.preReleaseIdentifiers.size()) + { return 1; - else if (i >= lhs.preReleaseIdentifiers.size()) + } + if (i >= lhs.preReleaseIdentifiers.size()) + { return -1; + } std::string const& left(lhs.preReleaseIdentifiers[i]); std::string const& right(rhs.preReleaseIdentifiers[i]); // Numeric identifiers have lower precedence if (!isNumeric(left) && isNumeric(right)) + { return 1; - else if (isNumeric(left) && !isNumeric(right)) + } + if (isNumeric(left) && !isNumeric(right)) + { return -1; + } if (isNumeric(left)) { @@ -284,9 +308,13 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) int const iRight(lexicalCastThrow(right)); if (iLeft > iRight) + { return 1; - else if (iLeft < iRight) + } + if (iLeft < iRight) + { return -1; + } } else { diff --git a/src/libxrpl/beast/net/IPEndpoint.cpp b/src/libxrpl/beast/net/IPEndpoint.cpp index 992da0041b..f8352f4318 100644 --- a/src/libxrpl/beast/net/IPEndpoint.cpp +++ b/src/libxrpl/beast/net/IPEndpoint.cpp @@ -95,10 +95,14 @@ operator>>(std::istream& is, Endpoint& endpoint) char i{0}; char readTo{0}; is.get(i); - if (i == '[') // we are an IPv6 endpoint + if (i == '[') + { // we are an IPv6 endpoint readTo = ']'; + } else + { addrStr += i; + } while (is && is.rdbuf()->in_avail() > 0 && is.get(i)) { @@ -166,7 +170,9 @@ operator>>(std::istream& is, Endpoint& endpoint) endpoint = Endpoint(addr, port); } else + { endpoint = Endpoint(addr); + } return is; } diff --git a/src/libxrpl/beast/utility/beast_Journal.cpp b/src/libxrpl/beast/utility/beast_Journal.cpp index f9ee0cdb73..7164fcfb06 100644 --- a/src/libxrpl/beast/utility/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/beast_Journal.cpp @@ -124,9 +124,13 @@ Journal::ScopedStream::~ScopedStream() if (!s.empty()) { if (s == "\n") + { m_sink.write(m_level, ""); + } else + { m_sink.write(m_level, s); + } } } diff --git a/src/libxrpl/beast/utility/beast_PropertyStream.cpp b/src/libxrpl/beast/utility/beast_PropertyStream.cpp index f1edb4c4ef..454b9d1323 100644 --- a/src/libxrpl/beast/utility/beast_PropertyStream.cpp +++ b/src/libxrpl/beast/utility/beast_PropertyStream.cpp @@ -237,9 +237,13 @@ PropertyStream::Source::write(PropertyStream& stream, std::string const& path) return; if (result.second) + { result.first->write(stream); + } else + { result.first->write_one(stream); + } } std::pair @@ -301,9 +305,13 @@ PropertyStream::Source::peel_name(std::string* path) std::string s(first, pos); if (pos != last) + { *path = std::string(pos + 1, last); + } else + { *path = std::string(); + } return s; } @@ -371,9 +379,13 @@ void PropertyStream::add(std::string const& key, bool value) { if (value) + { add(key, "true"); + } else + { add(key, "false"); + } } void @@ -464,9 +476,13 @@ void PropertyStream::add(bool value) { if (value) + { add("true"); + } else + { add("false"); + } } void diff --git a/src/libxrpl/core/detail/Workers.cpp b/src/libxrpl/core/detail/Workers.cpp index a5e331bd44..c037169a29 100644 --- a/src/libxrpl/core/detail/Workers.cpp +++ b/src/libxrpl/core/detail/Workers.cpp @@ -205,11 +205,9 @@ Workers::Worker::run() // We got paused break; } - else - { - // Undo our decrement - ++m_workers.m_pauseCount; - } + + // Undo our decrement + ++m_workers.m_pauseCount; } // We couldn't pause so we must have gotten diff --git a/src/libxrpl/crypto/RFC1751.cpp b/src/libxrpl/crypto/RFC1751.cpp index a21bc71c31..f7c1e675cb 100644 --- a/src/libxrpl/crypto/RFC1751.cpp +++ b/src/libxrpl/crypto/RFC1751.cpp @@ -285,13 +285,21 @@ RFC1751::standard(std::string& strWord) for (auto& letter : strWord) { if (islower(static_cast(letter))) + { letter = toupper(static_cast(letter)); + } else if (letter == '1') + { letter = 'L'; + } else if (letter == '0') + { letter = 'O'; + } else if (letter == '5') + { letter = 'S'; + } } } diff --git a/src/libxrpl/json/Writer.cpp b/src/libxrpl/json/Writer.cpp index ee3d6f97a8..6ff5a130dd 100644 --- a/src/libxrpl/json/Writer.cpp +++ b/src/libxrpl/json/Writer.cpp @@ -25,7 +25,7 @@ std::map jsonSpecialCharacterEscape = { {'\r', "\\r"}, {'\t', "\\t"}}; -static size_t const jsonEscapeLength = 2; +size_t const jsonEscapeLength = 2; // All other JSON punctuation. char const closeBrace = '}'; @@ -36,7 +36,7 @@ char const openBrace = '{'; char const openBracket = '['; char const quote = '"'; -static auto const integralFloatsBecomeInts = false; +auto const integralFloatsBecomeInts = false; size_t lengthWithoutTrailingZeros(std::string const& s) @@ -137,9 +137,13 @@ public: check(false, "Not an " + ((type == array ? "array: " : "object: ") + message)); } if (stack_.top().isFirst) + { stack_.top().isFirst = false; + } else + { output_({&comma, 1}); + } } void diff --git a/src/libxrpl/json/json_reader.cpp b/src/libxrpl/json/json_reader.cpp index 1195816516..4c2a27400f 100644 --- a/src/libxrpl/json/json_reader.cpp +++ b/src/libxrpl/json/json_reader.cpp @@ -278,9 +278,13 @@ Reader::skipSpaces() Char c = *current_; if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + { ++current_; + } else + { break; + } } } @@ -293,8 +297,10 @@ Reader::match(Location pattern, int patternLength) int index = patternLength; while (index--) + { if (current_[index] != pattern[index]) return false; + } current_ += patternLength; return true; @@ -384,9 +390,13 @@ Reader::readString() c = getNextChar(); if (c == '\\') + { getNextChar(); + } else if (c == '"') + { break; + } } return c == '"'; @@ -578,9 +588,13 @@ Reader::decodeNumber(Token& token) // If it's representable as a signed integer, construct it as one. if (value <= Value::maxInt) + { currentValue() = static_cast(value); + } else + { currentValue() = static_cast(value); + } } return true; @@ -646,8 +660,10 @@ Reader::decodeString(Token& token, std::string& decoded) Char c = *current++; if (c == '"') + { break; - else if (c == '\\') + } + if (c == '\\') { if (current == end) return addError("Empty escape sequence in string", token, current); @@ -721,19 +737,23 @@ Reader::decodeUnicodeCodePoint(Token& token, Location& current, Location end, un { // surrogate pairs if (end - current < 6) + { return addError( "additional six characters expected to parse unicode surrogate " "pair.", token, current); + } unsigned int surrogatePair = 0; if (*current != '\\' || *(current + 1) != 'u') + { return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current); + } current += 2; // skip two characters checked above @@ -754,8 +774,10 @@ Reader::decodeUnicodeEscapeSequence( unsigned int& unicode) { if (end - current < 4) + { return addError( "Bad unicode escape sequence in string: four digits expected.", token, current); + } unicode = 0; @@ -765,17 +787,25 @@ Reader::decodeUnicodeEscapeSequence( unicode *= 16; if (c >= '0' && c <= '9') + { unicode += c - '0'; + } else if (c >= 'a' && c <= 'f') + { unicode += c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') + { unicode += c - 'A' + 10; + } else + { return addError( "Bad unicode escape sequence in string: hexadecimal digit " "expected.", token, current); + } } return true; diff --git a/src/libxrpl/json/json_value.cpp b/src/libxrpl/json/json_value.cpp index 88542f530d..94b077d224 100644 --- a/src/libxrpl/json/json_value.cpp +++ b/src/libxrpl/json/json_value.cpp @@ -98,8 +98,11 @@ Value::CZString::CZString(CZString const& other) other.index_ != noDuplication && other.cstr_ != 0 ? valueAllocator()->makeMemberName(other.cstr_) : other.cstr_) - , index_( - other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_) + , index_([&]() -> int { + if (!other.cstr_) + return other.index_; + return other.index_ == noDuplication ? noDuplication : duplicate; + }()) { } @@ -254,7 +257,9 @@ Value::Value(Value const& other) : type_(other.type_) allocated_ = true; } else + { value_.string_ = 0; + } break; @@ -351,7 +356,9 @@ integerCmp(Int i, UInt ui) return -1; // Now we can safely compare. - return (i < ui) ? -1 : (i == ui) ? 0 : 1; + if (i < ui) + return -1; + return (i == ui) ? 0 : 1; } bool @@ -360,9 +367,13 @@ operator<(Value const& x, Value const& y) if (auto signum = x.type_ - y.type_) { if (x.type_ == intValue && y.type_ == uintValue) + { signum = integerCmp(x.value_.int_, y.value_.uint_); + } else if (x.type_ == uintValue && y.type_ == intValue) + { signum = -integerCmp(y.value_.int_, x.value_.uint_); + } return signum < 0; } @@ -696,7 +707,7 @@ Value::asBool() const case arrayValue: case objectValue: - return value_.map_->size() != 0; + return !value_.map_->empty(); // LCOV_EXCL_START default: @@ -743,10 +754,10 @@ Value::isConvertibleTo(ValueType other) const (other == nullValue && (!value_.string_ || value_.string_[0] == 0)); case arrayValue: - return other == arrayValue || (other == nullValue && value_.map_->size() == 0); + return other == arrayValue || (other == nullValue && value_.map_->empty()); case objectValue: - return other == objectValue || (other == nullValue && value_.map_->size() == 0); + return other == objectValue || (other == nullValue && value_.map_->empty()); // LCOV_EXCL_START default: diff --git a/src/libxrpl/json/json_valueiterator.cpp b/src/libxrpl/json/json_valueiterator.cpp index e40e674ee7..e49ad50f9a 100644 --- a/src/libxrpl/json/json_valueiterator.cpp +++ b/src/libxrpl/json/json_valueiterator.cpp @@ -13,7 +13,7 @@ namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) +ValueIteratorBase::ValueIteratorBase() : isNull_(true) { } diff --git a/src/libxrpl/json/json_writer.cpp b/src/libxrpl/json/json_writer.cpp index 8ba2576552..66507f0111 100644 --- a/src/libxrpl/json/json_writer.cpp +++ b/src/libxrpl/json/json_writer.cpp @@ -304,7 +304,9 @@ StyledWriter::writeValue(Value const& value) Value::Members members(value.getMemberNames()); if (members.empty()) + { pushValue("{}"); + } else { writeWithIndent("{"); @@ -339,7 +341,9 @@ StyledWriter::writeArrayValue(Value const& value) unsigned size = value.size(); if (size == 0) + { pushValue("[]"); + } else { bool isArrayMultiLine = isMultilineArray(value); @@ -356,7 +360,9 @@ StyledWriter::writeArrayValue(Value const& value) Value const& childValue = value[index]; if (hasChildValue) + { writeWithIndent(childValues_[index]); + } else { writeIndent(); @@ -429,9 +435,13 @@ void StyledWriter::pushValue(std::string const& value) { if (addChildValues_) + { childValues_.push_back(value); + } else + { document_ += value; + } } void @@ -529,7 +539,9 @@ StyledStreamWriter::writeValue(Value const& value) Value::Members members(value.getMemberNames()); if (members.empty()) + { pushValue("{}"); + } else { writeWithIndent("{"); @@ -564,7 +576,9 @@ StyledStreamWriter::writeArrayValue(Value const& value) unsigned size = value.size(); if (size == 0) + { pushValue("[]"); + } else { bool isArrayMultiLine = isMultilineArray(value); @@ -581,7 +595,9 @@ StyledStreamWriter::writeArrayValue(Value const& value) Value const& childValue = value[index]; if (hasChildValue) + { writeWithIndent(childValues_[index]); + } else { writeIndent(); @@ -654,9 +670,13 @@ void StyledStreamWriter::pushValue(std::string const& value) { if (addChildValues_) + { childValues_.push_back(value); + } else + { *document_ << value; + } } void diff --git a/src/libxrpl/ledger/ApplyStateTable.cpp b/src/libxrpl/ledger/ApplyStateTable.cpp index 8c1f8d64d2..a0074c0b53 100644 --- a/src/libxrpl/ledger/ApplyStateTable.cpp +++ b/src/libxrpl/ledger/ApplyStateTable.cpp @@ -169,9 +169,11 @@ ApplyStateTable::apply( "xrpl::detail::ApplyStateTable::apply : valid nodes for " "modification"); - if (curNode->isThreadedType(to.rules())) // thread transaction to node - // item modified + if (curNode->isThreadedType(to.rules())) + { // thread transaction to node + // item modified threadItem(meta, curNode); + } STObject prevs(sfPreviousFields); for (auto const& obj : *origNode) diff --git a/src/libxrpl/ledger/BookListeners.cpp b/src/libxrpl/ledger/BookListeners.cpp index 9ba25b783a..22b78e46bb 100644 --- a/src/libxrpl/ledger/BookListeners.cpp +++ b/src/libxrpl/ledger/BookListeners.cpp @@ -38,7 +38,9 @@ BookListeners::publish(MultiApiJson const& jvObj, hash_set& haveP ++it; } else + { it = mListeners.erase(it); + } } } diff --git a/src/libxrpl/ledger/CachedView.cpp b/src/libxrpl/ledger/CachedView.cpp index 12704d227e..5c15ccdac4 100644 --- a/src/libxrpl/ledger/CachedView.cpp +++ b/src/libxrpl/ledger/CachedView.cpp @@ -40,11 +40,17 @@ CachedViewImpl::read(Keylet const& k) const // If the sle is null, then a failure must have occurred in base_.read() XRPL_ASSERT(sle || baseRead, "xrpl::CachedView::read : null SLE result from base"); if (cacheHit && baseRead) + { hitsexpired.increment(); + } else if (cacheHit) + { hits.increment(); + } else + { misses.increment(); + } if (!cacheHit) { diff --git a/src/libxrpl/ledger/CredentialHelpers.cpp b/src/libxrpl/ledger/CredentialHelpers.cpp index 1f32f5f1fa..0782eda67d 100644 --- a/src/libxrpl/ledger/CredentialHelpers.cpp +++ b/src/libxrpl/ledger/CredentialHelpers.cpp @@ -186,10 +186,12 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject) foundExpired = true; continue; } - else if (sleCredential->getFlags() & lsfAccepted) + if (sleCredential->getFlags() & lsfAccepted) + { return tesSUCCESS; - else - continue; + } + + continue; } } @@ -337,9 +339,11 @@ verifyDepositPreauth( if (src != dst) { if (!view.exists(keylet::depositPreauth(dst, src))) + { return !credentialsPresent ? tecNO_PERMISSION : credentials::authorizedDepositPreauth( view, tx.getFieldV256(sfCredentialIDs), dst); + } } } diff --git a/src/libxrpl/ledger/OpenView.cpp b/src/libxrpl/ledger/OpenView.cpp index 5b94be5da8..b5e358053c 100644 --- a/src/libxrpl/ledger/OpenView.cpp +++ b/src/libxrpl/ledger/OpenView.cpp @@ -185,7 +185,7 @@ OpenView::txsEnd() const -> std::unique_ptr bool OpenView::txExists(key_type const& key) const { - return txs_.find(key) != txs_.end(); + return txs_.contains(key); } auto @@ -198,9 +198,13 @@ OpenView::txRead(key_type const& key) const -> tx_type auto stx = std::make_shared(SerialIter{item.txn->slice()}); decltype(tx_type::second) sto; if (item.meta) + { sto = std::make_shared(SerialIter{item.meta->slice()}, sfMetadata); + } else + { sto = nullptr; + } return {std::move(stx), std::move(sto)}; } diff --git a/src/libxrpl/ledger/PaymentSandbox.cpp b/src/libxrpl/ledger/PaymentSandbox.cpp index e211917466..1f84da1dcb 100644 --- a/src/libxrpl/ledger/PaymentSandbox.cpp +++ b/src/libxrpl/ledger/PaymentSandbox.cpp @@ -11,9 +11,11 @@ auto DeferredCredits::makeKey(AccountID const& a1, AccountID const& a2, Currency const& c) -> Key { if (a1 < a2) + { return std::make_tuple(a1, a2, c); - else - return std::make_tuple(a2, a1, c); + } + + return std::make_tuple(a2, a1, c); } void @@ -53,9 +55,13 @@ DeferredCredits::credit( // only record the balance the first time, do not record it here auto& v = i->second; if (sender < receiver) + { v.highAcctCredits += amount; + } else + { v.lowAcctCredits += amount; + } } } @@ -101,11 +107,9 @@ DeferredCredits::adjustments( result.emplace(v.highAcctCredits, v.lowAcctCredits, v.lowAcctOrigBalance); return result; } - else - { - result.emplace(v.lowAcctCredits, v.highAcctCredits, -v.lowAcctOrigBalance); - return result; - } + + result.emplace(v.lowAcctCredits, v.highAcctCredits, -v.lowAcctOrigBalance); + return result; } void @@ -179,11 +183,13 @@ PaymentSandbox::balanceHook( adjustedAmt.setIssuer(amount.getIssuer()); if (isXRP(issuer) && adjustedAmt < beast::zero) + { // A calculated negative XRP balance is not an error case. Consider a // payment snippet that credits a large XRP amount and then debits the // same amount. The credit can't be used but we subtract the debit and // calculate a negative value. It's not an error case. adjustedAmt.clear(); + } return adjustedAmt; } diff --git a/src/libxrpl/ledger/RawStateTable.cpp b/src/libxrpl/ledger/RawStateTable.cpp index fcd8126c87..b411a25b00 100644 --- a/src/libxrpl/ledger/RawStateTable.cpp +++ b/src/libxrpl/ledger/RawStateTable.cpp @@ -94,9 +94,13 @@ public: dereference() const override { if (!sle1_) + { return sle0_; - else if (!sle0_) + } + if (!sle0_) + { return sle1_; + } if (sle1_->key() <= sle0_->key()) return sle1_; return sle0_; @@ -108,9 +112,13 @@ private: { ++iter0_; if (iter0_ == end0_) + { sle0_ = nullptr; + } else + { sle0_ = *iter0_; + } } void @@ -118,9 +126,13 @@ private: { ++iter1_; if (iter1_ == end1_) + { sle1_ = nullptr; + } else + { sle1_ = iter1_->second.sle; + } } void diff --git a/src/libxrpl/ledger/View.cpp b/src/libxrpl/ledger/View.cpp index 67aa4f5978..e76f0bfddc 100644 --- a/src/libxrpl/ledger/View.cpp +++ b/src/libxrpl/ledger/View.cpp @@ -51,9 +51,13 @@ internalDirNext( } 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"); @@ -83,9 +87,13 @@ internalDirFirst( 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; @@ -180,9 +188,13 @@ 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()); } @@ -381,7 +393,7 @@ getLineIfUsable( { return nullptr; // LCOV_EXCL_LINE } - else if (sleIssuer->isFieldPresent(sfAMMID)) + if (sleIssuer->isFieldPresent(sfAMMID)) { auto const sleAmm = view.read(keylet::amm((*sleIssuer)[sfAMMID])); @@ -457,9 +469,11 @@ accountHolds( 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 = @@ -514,9 +528,13 @@ accountHolds( 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)}; @@ -751,8 +769,10 @@ forEachItemAfter( 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; @@ -791,9 +811,13 @@ 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()); } @@ -1168,9 +1192,13 @@ canAddHolding(ReadView const& view, Issue const& issue) auto const issuer = view.read(keylet::account(issue.getIssuer())); if (!issuer) + { return terNO_ACCOUNT; - else if (!issuer->isFlag(lsfDefaultRipple)) + } + if (!issuer->isFlag(lsfDefaultRipple)) + { return terNO_RIPPLE; + } return tesSUCCESS; } @@ -1526,11 +1554,15 @@ authorizeMPToken( // 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); @@ -2319,15 +2351,13 @@ accountSendMultiIOU( { return TER{tecFAILED_PROCESSING}; } - else - { - auto const sndBal = sender->getFieldAmount(sfBalance); - view.creditHook(senderID, xrpAccount(), takeFromSender, sndBal); - // Decrement XRP balance. - sender->setFieldAmount(sfBalance, sndBal - takeFromSender); - view.update(sender); - } + 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()) @@ -2375,7 +2405,9 @@ rippleCreditMPT( view.update(sle); } else + { return tecNO_AUTH; + } } if (uReceiverID == issuer) @@ -2388,7 +2420,9 @@ rippleCreditMPT( view.update(sleIssuance); } else + { return tecINTERNAL; // LCOV_EXCL_LINE + } } else { @@ -2399,7 +2433,9 @@ rippleCreditMPT( view.update(sle); } else + { return tecNO_AUTH; + } } return tesSUCCESS; @@ -2599,9 +2635,13 @@ accountSend( 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()); } @@ -2620,9 +2660,13 @@ accountSendMulti( 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()); } @@ -2725,12 +2769,14 @@ issueIOU( // 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); @@ -2898,9 +2944,11 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account, issuerAccount && (*issuerAccount)[sfFlags] & lsfRequireAuth) { if (trustLine) + { return ((*trustLine)[sfFlags] & ((account > issue.account) ? lsfLowAuth : lsfHighAuth)) ? tesSUCCESS : TER{tecNO_AUTH}; + } return TER{tecNO_LINE}; } @@ -2948,9 +2996,13 @@ requireAuth( 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)) @@ -2974,11 +3026,15 @@ requireAuth( sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth, "xrpl::requireAuth : issuance requires authorization"); // ter = tefINTERNAL | tecOBJECT_NOT_FOUND | tecNO_AUTH | tecEXPIRED - if (auto const ter = credentials::validDomain(view, *maybeDomainID, account); - isTesSuccess(ter)) + auto const ter = credentials::validDomain(view, *maybeDomainID, account); + if (isTesSuccess(ter)) + { return ter; // Note: sleToken might be null - else if (!sleToken) + } + 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. } @@ -3045,14 +3101,14 @@ enforceMPTokenAuthorization( // Either way, return tecNO_AUTH and there is nothing else to do return expired ? tecEXPIRED : tecNO_AUTH; } - else if (!authorizedByDomain && maybeDomainID.has_value()) + 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; } - else if (!authorizedByDomain) + if (!authorizedByDomain) { // We found an MPToken, but sfDomainID is not set, so this is a classic // MPToken which requires authorization by the token issuer. @@ -3064,7 +3120,7 @@ enforceMPTokenAuthorization( return tecNO_AUTH; } - else if (authorizedByDomain && sleToken != nullptr) + if (authorizedByDomain && sleToken != nullptr) { // Found an MPToken, authorized by the domain. Ignore authorization flag // lsfMPTAuthorized because it is meaningless. Return tesSUCCESS @@ -3073,7 +3129,7 @@ enforceMPTokenAuthorization( "xrpl::enforceMPTokenAuthorization : found MPToken for domain"); return tesSUCCESS; } - else if (authorizedByDomain) + if (authorizedByDomain) { // Could not find MPToken but there should be one because we are // authorized by domain. Proceed to create it, then return tesSUCCESS @@ -3314,9 +3370,11 @@ assetsToSharesDeposit( 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(); @@ -3339,8 +3397,10 @@ sharesToAssetsDeposit( 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; @@ -3455,9 +3515,13 @@ rippleLockEscrowMPT( } // LCOV_EXCL_STOP if (sle->isFieldPresent(sfLockedAmount)) + { (*sle)[sfLockedAmount] += pay; + } else + { sle->setFieldU64(sfLockedAmount, pay); + } view.update(sle); } @@ -3478,9 +3542,13 @@ rippleLockEscrowMPT( } // LCOV_EXCL_STOP if (sleIssuance->isFieldPresent(sfLockedAmount)) + { (*sleIssuance)[sfLockedAmount] += pay; + } else + { sleIssuance->setFieldU64(sfLockedAmount, pay); + } view.update(sleIssuance); } @@ -3497,8 +3565,10 @@ rippleUnlockEscrowMPT( 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(); @@ -3533,9 +3603,13 @@ rippleUnlockEscrowMPT( auto const newLocked = locked - redeem; if (newLocked == 0) + { sleIssuance->makeFieldAbsent(sfLockedAmount); + } else + { sleIssuance->setFieldU64(sfLockedAmount, newLocked); + } view.update(sleIssuance); } @@ -3588,42 +3662,44 @@ rippleUnlockEscrowMPT( "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 { - // 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); + 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 diff --git a/src/libxrpl/nodestore/backend/MemoryFactory.cpp b/src/libxrpl/nodestore/backend/MemoryFactory.cpp index b11d90610a..0366fe3573 100644 --- a/src/libxrpl/nodestore/backend/MemoryFactory.cpp +++ b/src/libxrpl/nodestore/backend/MemoryFactory.cpp @@ -142,9 +142,13 @@ public: std::shared_ptr nObj; Status status = fetch(h, &nObj); if (status != ok) + { results.push_back({}); + } else + { results.push_back(nObj); + } } return {results, ok}; diff --git a/src/libxrpl/nodestore/backend/NuDBFactory.cpp b/src/libxrpl/nodestore/backend/NuDBFactory.cpp index 229bf8b67b..2d8cffa85a 100644 --- a/src/libxrpl/nodestore/backend/NuDBFactory.cpp +++ b/src/libxrpl/nodestore/backend/NuDBFactory.cpp @@ -216,9 +216,13 @@ public: std::shared_ptr nObj; Status status = fetch(h, &nObj); if (status != ok) + { results.push_back({}); + } else + { results.push_back(nObj); + } } return {results, ok}; diff --git a/src/libxrpl/nodestore/backend/RocksDBFactory.cpp b/src/libxrpl/nodestore/backend/RocksDBFactory.cpp index 01bc74f5ed..67c329bb4a 100644 --- a/src/libxrpl/nodestore/backend/RocksDBFactory.cpp +++ b/src/libxrpl/nodestore/backend/RocksDBFactory.cpp @@ -166,8 +166,10 @@ public: auto const s = rocksdb::GetBlockBasedTableOptionsFromString( config_options, table_options, get(keyValues, "bbt_options"), &table_options); if (!s.ok()) + { Throw( std::string("Unable to set RocksDB bbt_options: ") + s.ToString()); + } } m_options.table_factory.reset(NewBlockBasedTableFactory(table_options)); @@ -177,8 +179,10 @@ public: auto const s = rocksdb::GetOptionsFromString(m_options, get(keyValues, "options"), &m_options); if (!s.ok()) + { Throw( std::string("Unable to set RocksDB options: ") + s.ToString()); + } } std::string s1, s2; @@ -210,8 +214,10 @@ public: m_options.create_if_missing = createIfMissing; rocksdb::Status status = rocksdb::DB::Open(m_options, m_name, &db); if (!status.ok() || !db) + { Throw( std::string("Unable to open/create RocksDB: ") + status.ToString()); + } m_db.reset(db); } @@ -304,9 +310,13 @@ public: std::shared_ptr nObj; Status status = fetch(h, &nObj); if (status != ok) + { results.push_back({}); + } else + { results.push_back(nObj); + } } return {results, ok}; diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 4d904a5e43..f91e164c92 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -250,18 +250,22 @@ FeatureCollections::registerFeature(std::string const& name, Supported support, supported.emplace(name, vote); if (vote == VoteBehavior::DefaultYes) + { ++upVotes; + } else + { ++downVotes; + } } check(upVotes + downVotes == supported.size(), "Feature counting logic broke"); check(supported.size() <= features.size(), "More supported features than defined features"); check(features.size() == all.size(), "The 'all' features list is populated incorrectly"); return f; } - else - // Each feature should only be registered once - LogicError("Duplicate feature registration"); + + // Each feature should only be registered once + LogicError("Duplicate feature registration"); } /** Tell FeatureCollections when registration is complete. */ @@ -302,7 +306,7 @@ FeatureCollections::featureToName(uint256 const& f) const return feature ? feature->name : to_string(f); } -static FeatureCollections featureCollections; +FeatureCollections featureCollections; } // namespace diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 45ab20f057..aabe8395ae 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -137,7 +137,7 @@ getQuality(uint256 const& uBase) uint256 getTicketIndex(AccountID const& account, std::uint32_t ticketSeq) { - return indexHash(LedgerNameSpace::TICKET, account, std::uint32_t(ticketSeq)); + return indexHash(LedgerNameSpace::TICKET, account, ticketSeq); } uint256 diff --git a/src/libxrpl/protocol/Issue.cpp b/src/libxrpl/protocol/Issue.cpp index 1a56007729..c73c6c8513 100644 --- a/src/libxrpl/protocol/Issue.cpp +++ b/src/libxrpl/protocol/Issue.cpp @@ -25,11 +25,17 @@ Issue::getText() const ret += "/"; if (isXRP(account)) + { ret += "0"; + } else if (account == noAccount()) + { ret += "1"; + } else + { ret += to_string(account); + } } return ret; diff --git a/src/libxrpl/protocol/NFTokenID.cpp b/src/libxrpl/protocol/NFTokenID.cpp index 66f05a81fc..d867cdb8c9 100644 --- a/src/libxrpl/protocol/NFTokenID.cpp +++ b/src/libxrpl/protocol/NFTokenID.cpp @@ -154,7 +154,7 @@ insertNFTokenID( { std::vector result = getNFTokenIDFromDeletedOffer(transactionMeta); - if (result.size() > 0) + if (!result.empty()) response[jss::nftoken_id] = to_string(result.front()); } else if (type == ttNFTOKEN_CANCEL_OFFER) diff --git a/src/libxrpl/protocol/Permissions.cpp b/src/libxrpl/protocol/Permissions.cpp index cce7ab5058..4137c73624 100644 --- a/src/libxrpl/protocol/Permissions.cpp +++ b/src/libxrpl/protocol/Permissions.cpp @@ -68,10 +68,12 @@ Permission::Permission() }; for ([[maybe_unused]] auto const& permission : granularPermissionMap_) + { XRPL_ASSERT( permission.second > UINT16_MAX, "xrpl::Permission::granularPermissionMap_ : granular permission " "value must not exceed the maximum uint16_t value."); + } } Permission const& @@ -126,7 +128,7 @@ Permission::getGranularTxType(GranularPermissionType const& gpType) const return std::nullopt; } -std::optional> const +std::optional> Permission::getTxFeature(TxType txType) const { auto const txFeaturesIt = txFeatureMap_.find(txType); @@ -145,8 +147,10 @@ Permission::isDelegable(std::uint32_t const& permissionValue, Rules const& rules auto const granularPermission = getGranularName(static_cast(permissionValue)); if (granularPermission) + { // granular permissions are always allowed to be delegated return true; + } auto const txType = permissionToTxType(permissionValue); auto const it = delegableTx_.find(txType); diff --git a/src/libxrpl/protocol/PublicKey.cpp b/src/libxrpl/protocol/PublicKey.cpp index 3251cb84ac..2c63ddac64 100644 --- a/src/libxrpl/protocol/PublicKey.cpp +++ b/src/libxrpl/protocol/PublicKey.cpp @@ -171,9 +171,11 @@ ed25519Canonical(Slice const& sig) PublicKey::PublicKey(Slice const& slice) { if (slice.size() < size_) + { LogicError( "PublicKey::PublicKey - Input slice cannot be an undersized " "buffer"); + } if (!publicKeyType(slice)) LogicError("PublicKey::PublicKey invalid type"); @@ -270,7 +272,7 @@ verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept { return verifyDigest(publicKey, sha512Half(m), sig); } - else if (*type == KeyType::ed25519) + if (*type == KeyType::ed25519) { if (!ed25519Canonical(sig)) return false; diff --git a/src/libxrpl/protocol/Rules.cpp b/src/libxrpl/protocol/Rules.cpp index 5a97a33185..4ef052d2cc 100644 --- a/src/libxrpl/protocol/Rules.cpp +++ b/src/libxrpl/protocol/Rules.cpp @@ -77,9 +77,9 @@ public: bool enabled(uint256 const& feature) const { - if (presets_.count(feature) > 0) + if (presets_.contains(feature)) return true; - return set_.count(feature) > 0; + return set_.contains(feature); } bool diff --git a/src/libxrpl/protocol/STAccount.cpp b/src/libxrpl/protocol/STAccount.cpp index 9570191273..ffd0b5d3c8 100644 --- a/src/libxrpl/protocol/STAccount.cpp +++ b/src/libxrpl/protocol/STAccount.cpp @@ -16,7 +16,7 @@ namespace xrpl { -STAccount::STAccount() : STBase(), value_(beast::zero), default_(true) +STAccount::STAccount() : value_(beast::zero), default_(true) { } diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index 5990e1d7d4..92ce129825 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -223,9 +223,13 @@ STAmount::STAmount(XRPAmount const& amount) : mAsset(xrpIssue()), mOffset(0), mIsNegative(amount < beast::zero) { if (mIsNegative) + { mValue = unsafe_cast(-amount.drops()); + } else + { mValue = unsafe_cast(amount.drops()); + } canonicalize(); } @@ -305,9 +309,13 @@ STAmount::operator=(IOUAmount const& iou) mOffset = iou.exponent(); mIsNegative = iou < beast::zero; if (mIsNegative) + { mValue = static_cast(-iou.mantissa()); + } else + { mValue = static_cast(iou.mantissa()); + } return *this; } @@ -722,9 +730,13 @@ STAmount::getText() const // Assemble the output: if (pre_from == pre_to) + { ret.append(1, '0'); + } else + { ret.append(pre_from, pre_to); + } if (post_to != post_from) { @@ -751,9 +763,13 @@ STAmount::add(Serializer& s) const XRPL_ASSERT(mOffset == 0, "xrpl::STAmount::add : zero offset"); if (!mIsNegative) + { s.add64(mValue | cPositive); + } else + { s.add64(mValue); + } } else if (mAsset.holds()) { @@ -767,11 +783,17 @@ STAmount::add(Serializer& s) const else { if (*this == beast::zero) + { s.add64(cIssuedCurrency); - else if (mIsNegative) // 512 = not native + } + else if (mIsNegative) + { // 512 = not native s.add64(mValue | (static_cast(mOffset + 512 + 97) << (64 - 10))); - else // 256 = positive + } + else + { // 256 = positive s.add64(mValue | (static_cast(mOffset + 512 + 256 + 97) << (64 - 10))); + } s.addBitString(mAsset.get().currency); s.addBitString(mAsset.get().account); } @@ -839,11 +861,17 @@ STAmount::canonicalize() mValue = mIsNegative ? -value : value; }; if (native()) + { set(XRPAmount{num}); + } else if (mAsset.holds()) + { set(MPTAmount{num}); + } else + { Throw("Unknown integral asset type"); + } mOffset = 0; } else @@ -859,9 +887,13 @@ STAmount::canonicalize() // N.B. do not move the overflow check to after the // multiplication if (native() && mValue > cMaxNativeN) + { Throw("Native currency amount out of range"); + } else if (!native() && mValue > maxMPTokenAmount) + { Throw("MPT amount out of range"); + } mValue *= 10; --mOffset; @@ -869,9 +901,13 @@ STAmount::canonicalize() } if (native() && mValue > cMaxNativeN) + { Throw("Native currency amount out of range"); + } else if (!native() && mValue > maxMPTokenAmount) + { Throw("MPT amount out of range"); + } return; } diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index 09993583be..aa97b6b3a2 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -33,9 +33,11 @@ STLedgerEntry::STLedgerEntry(Keylet const& k) : STObject(sfLedgerEntry), key_(k. auto const format = LedgerFormats::getInstance().findByType(type_); if (format == nullptr) + { Throw( "Attempt to create a SLE of unknown type " + std::to_string(safe_cast(k.type))); + } set(format->getSOTemplate()); @@ -118,8 +120,10 @@ STLedgerEntry::getJson(JsonOptions options) const ret[jss::index] = to_string(key_); if (getType() == ltMPTOKEN_ISSUANCE) + { ret[jss::mpt_issuance_id] = to_string(makeMptID(getFieldU32(sfSequence), getAccountID(sfIssuer))); + } return ret; } diff --git a/src/libxrpl/protocol/STNumber.cpp b/src/libxrpl/protocol/STNumber.cpp index 6d382bee9c..aab4bdc0f5 100644 --- a/src/libxrpl/protocol/STNumber.cpp +++ b/src/libxrpl/protocol/STNumber.cpp @@ -198,9 +198,13 @@ partsFromString(std::string const& number) { // we have an exponent if (match[6].matched && (match[6] == "-")) + { exponent -= boost::lexical_cast(std::string(match[7])); + } else + { exponent += boost::lexical_cast(std::string(match[7])); + } } return {mantissa, exponent, negative}; diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index 05d4d12503..fe9e95cc82 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -140,9 +140,13 @@ STObject::set(SOTemplate const& type) for (auto const& elem : type) { if (elem.style() != soeREQUIRED) + { v_.emplace_back(detail::nonPresentObject, elem.sField()); + } else + { v_.emplace_back(detail::defaultObject, elem.sField()); + } } } @@ -268,7 +272,7 @@ STObject::set(SerialIter& sit, int depth) } bool -STObject::hasMatchingEntry(STBase const& t) +STObject::hasMatchingEntry(STBase const& t) const { STBase const* o = peekAtPField(t.getFName()); @@ -290,16 +294,22 @@ STObject::getFullText() const ret += " = {"; } else + { ret = "{"; + } for (auto const& elem : v_) { if (elem->getSType() != STI_NOTPRESENT) { if (!first) + { ret += ", "; + } else + { first = false; + } ret += elem->getFullText(); } diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index b246daf48e..0bf0c827af 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -267,8 +267,10 @@ parseUint16( } } if (!ret) + { return parseUnsigned( field, json_name, fieldName, name, value, error); + } } catch (std::exception const&) { @@ -320,8 +322,10 @@ parseUint32( } } if (!ret) + { return parseUnsigned( field, json_name, fieldName, name, value, error); + } } catch (std::exception const&) { diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index bb4b9b3067..00a2acd788 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -199,8 +199,10 @@ STTx::getSeqProxy() const std::optional const ticketSeq{operator[](~sfTicketSequence)}; if (!ticketSeq) + { // No TicketSequence specified. Return the Sequence, whatever it is. return SeqProxy::sequence(seq); + } return SeqProxy{SeqProxy::ticket, *ticketSeq}; } @@ -337,8 +339,8 @@ STTx::getJson(JsonOptions options, bool binary) const ret[jss::hash] = to_string(getTransactionID()); return ret; } - else - return Json::Value{dataBin}; + + return Json::Value{dataBin}; } Json::Value ret = STObject::getJson(JsonOptions::none); @@ -500,9 +502,11 @@ multiSignHelper( errorWhat = e.what(); } if (!validSig) + { return Unexpected( std::string("Invalid signature on account ") + toBase58(accountID) + errorWhat.value_or("") + "."); + } } // All signatures verified. return {}; @@ -576,7 +580,7 @@ STTx::getBatchTransactionIDs() const // The list of inner ids is built once, then reused on subsequent calls. // After the list is built, it must always have the same size as the array // `sfRawTransactions`. The assert below verifies that. - if (batchTxnIds_.size() == 0) + if (batchTxnIds_.empty()) { for (STObject const& rb : getFieldArray(sfRawTransactions)) batchTxnIds_.push_back(rb.getHash(HashPrefix::transactionID)); diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index 6218bb6db6..255514d70c 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -61,9 +61,13 @@ STVar::operator=(STVar const& rhs) { destroy(); if (rhs.p_) + { p_ = rhs.p_->copy(max_size, &d_); + } else + { p_ = nullptr; + } } return *this; @@ -116,9 +120,13 @@ void STVar::destroy() { if (on_heap()) + { delete p_; + } else + { p_->~STBase(); + } p_ = nullptr; } diff --git a/src/libxrpl/protocol/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp index 886fed5d2d..6357e2f2cb 100644 --- a/src/libxrpl/protocol/STVector256.cpp +++ b/src/libxrpl/protocol/STVector256.cpp @@ -19,8 +19,10 @@ STVector256::STVector256(SerialIter& sit, SField const& name) : STBase(name) auto const slice = sit.getSlice(sit.getVLDataLength()); if (slice.size() % uint256::size() != 0) + { Throw( "Bad serialization for STVector256: " + std::to_string(slice.size())); + } auto const cnt = slice.size() / uint256::size(); diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index 4415f96484..08d221f75b 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -112,8 +112,10 @@ Serializer::addFieldID(int type, int name) if (type < 16) { - if (name < 16) // common type, common name + if (name < 16) + { // common type, common name mData.push_back(static_cast((type << 4) | name)); + } else { // common type, uncommon name @@ -187,7 +189,7 @@ int Serializer::addVL(Slice const& slice) { int ret = addEncoded(slice.size()); - if (slice.size()) + if (!slice.empty()) addRaw(slice.data(), slice.size()); return ret; } @@ -230,7 +232,9 @@ Serializer::addEncoded(int length) numBytes = 3; } else + { Throw("lenlen"); + } return addRaw(&bytes[0], numBytes); } diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index 868c45e46c..b46591725f 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -615,7 +615,7 @@ encodeBase58Token( { return Unexpected(TokenCodecErrc::inputTooLarge); } - if (input.size() == 0) + if (input.empty()) { return Unexpected(TokenCodecErrc::inputTooSmall); } diff --git a/src/libxrpl/rdb/SociDB.cpp b/src/libxrpl/rdb/SociDB.cpp index 3ba0d4c980..baadeef00a 100644 --- a/src/libxrpl/rdb/SociDB.cpp +++ b/src/libxrpl/rdb/SociDB.cpp @@ -81,9 +81,13 @@ void open(soci::session& s, std::string const& beName, std::string const& connectionString) { if (beName == "sqlite") + { s.open(soci::sqlite3, connectionString); + } else + { Throw("Unsupported soci backend: " + beName); + } } static sqlite_api::sqlite3* @@ -143,18 +147,26 @@ void convert(std::vector const& from, soci::blob& to) { if (!from.empty()) + { to.write(0, reinterpret_cast(&from[0]), from.size()); + } else + { to.trim(0); + } } void convert(std::string const& from, soci::blob& to) { if (!from.empty()) + { to.write(0, from.data(), from.size()); + } else + { to.trim(0); + } } namespace { diff --git a/src/libxrpl/server/InfoSub.cpp b/src/libxrpl/server/InfoSub.cpp index 0ec432883d..5857e4d6ae 100644 --- a/src/libxrpl/server/InfoSub.cpp +++ b/src/libxrpl/server/InfoSub.cpp @@ -52,7 +52,7 @@ InfoSub::getConsumer() } std::uint64_t -InfoSub::getSeq() +InfoSub::getSeq() const { return mSeq; } @@ -68,9 +68,13 @@ InfoSub::insertSubAccountInfo(AccountID const& account, bool rt) std::lock_guard sl(mLock); if (rt) + { realTimeSubscriptions_.insert(account); + } else + { normalSubscriptions_.insert(account); + } } void @@ -79,9 +83,13 @@ InfoSub::deleteSubAccountInfo(AccountID const& account, bool rt) std::lock_guard sl(mLock); if (rt) + { realTimeSubscriptions_.erase(account); + } else + { normalSubscriptions_.erase(account); + } } bool diff --git a/src/libxrpl/server/LoadFeeTrack.cpp b/src/libxrpl/server/LoadFeeTrack.cpp index e3867f36f5..e206b50863 100644 --- a/src/libxrpl/server/LoadFeeTrack.cpp +++ b/src/libxrpl/server/LoadFeeTrack.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace xrpl { @@ -19,14 +20,12 @@ LoadFeeTrack::raiseLocalFee() std::uint32_t const origFee = localTxnLoadFee_; // make sure this fee takes effect - if (localTxnLoadFee_ < remoteTxnLoadFee_) - localTxnLoadFee_ = remoteTxnLoadFee_; + localTxnLoadFee_ = std::max(localTxnLoadFee_, remoteTxnLoadFee_); // Increase slowly localTxnLoadFee_ += (localTxnLoadFee_ / lftFeeIncFraction); - if (localTxnLoadFee_ > lftFeeMax) - localTxnLoadFee_ = lftFeeMax; + localTxnLoadFee_ = std::min(localTxnLoadFee_, lftFeeMax); if (origFee == localTxnLoadFee_) return false; @@ -45,8 +44,7 @@ LoadFeeTrack::lowerLocalFee() // Reduce slowly localTxnLoadFee_ -= (localTxnLoadFee_ / lftFeeDecFraction); - if (localTxnLoadFee_ < lftNormalFee) - localTxnLoadFee_ = lftNormalFee; + localTxnLoadFee_ = std::max(localTxnLoadFee_, lftNormalFee); if (origFee == localTxnLoadFee_) return false; diff --git a/src/libxrpl/server/Port.cpp b/src/libxrpl/server/Port.cpp index 0cef9bed90..2d0b4ec257 100644 --- a/src/libxrpl/server/Port.cpp +++ b/src/libxrpl/server/Port.cpp @@ -44,7 +44,7 @@ operator<<(std::ostream& os, Port const& p) { os << "'" << p.name << "' (ip=" << p.ip << ":" << p.port << ", "; - if (p.admin_nets_v4.size() || p.admin_nets_v6.size()) + if (!p.admin_nets_v4.empty() || !p.admin_nets_v6.empty()) { os << "admin nets:"; for (auto const& net : p.admin_nets_v4) @@ -59,7 +59,7 @@ operator<<(std::ostream& os, Port const& p) } } - if (p.secure_gateway_nets_v4.size() || p.secure_gateway_nets_v6.size()) + if (!p.secure_gateway_nets_v4.empty() || !p.secure_gateway_nets_v6.empty()) { os << "secure_gateway nets:"; for (auto const& net : p.secure_gateway_nets_v4) diff --git a/src/libxrpl/shamap/SHAMap.cpp b/src/libxrpl/shamap/SHAMap.cpp index d5fa67fdac..a6aacfabc9 100644 --- a/src/libxrpl/shamap/SHAMap.cpp +++ b/src/libxrpl/shamap/SHAMap.cpp @@ -418,9 +418,13 @@ SHAMap::belowHelper( } auto inner = intr_ptr::static_pointer_cast(node); if (stack.empty()) + { stack.push({inner, SHAMapNodeID{}}); + } else + { stack.push({inner, stack.top().second.getChildNodeID(branch)}); + } for (int i = init; cmp(i);) { if (!inner->isEmptyBranch(i)) @@ -438,7 +442,9 @@ SHAMap::belowHelper( i = init; // descend and reset loop } else + { incr(i); // scan next branch + } } return nullptr; } @@ -1114,7 +1120,9 @@ SHAMap::dump(bool hash) const } } else + { ++leafCount; + } } while (!stack.empty()); JLOG(journal_.info()) << leafCount << " resident leaves"; diff --git a/src/libxrpl/shamap/SHAMapDelta.cpp b/src/libxrpl/shamap/SHAMapDelta.cpp index 7ef78d51c3..98a31fea55 100644 --- a/src/libxrpl/shamap/SHAMapDelta.cpp +++ b/src/libxrpl/shamap/SHAMapDelta.cpp @@ -42,8 +42,10 @@ SHAMap::walkBranch( // This is an inner node, add all non-empty branches auto inner = safe_downcast(node); for (int i = 0; i < 16; ++i) + { if (!inner->isEmptyBranch(i)) nodeStack.push({descendThrow(inner, i)}); + } } else { @@ -54,9 +56,13 @@ SHAMap::walkBranch( { // unmatched if (isFirstMap) + { differences.insert(std::make_pair(item->key(), DeltaRef(item, nullptr))); + } else + { differences.insert(std::make_pair(item->key(), DeltaRef(nullptr, item))); + } if (--maxCount <= 0) return false; @@ -65,9 +71,13 @@ SHAMap::walkBranch( { // non-matching items with same tag if (isFirstMap) + { differences.insert(std::make_pair(item->key(), DeltaRef(item, otherMapItem))); + } else + { differences.insert(std::make_pair(item->key(), DeltaRef(otherMapItem, item))); + } if (--maxCount <= 0) return false; @@ -85,12 +95,16 @@ SHAMap::walkBranch( if (!emptyBranch) { // otherMapItem was unmatched, must add - if (isFirstMap) // this is first map, so other item is from second + if (isFirstMap) + { // this is first map, so other item is from second differences.insert( std::make_pair(otherMapItem->key(), DeltaRef(nullptr, otherMapItem))); + } else + { differences.insert( std::make_pair(otherMapItem->key(), DeltaRef(otherMapItem, nullptr))); + } if (--maxCount <= 0) return false; @@ -179,6 +193,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const auto ours = safe_downcast(ourNode); auto other = safe_downcast(otherNode); for (int i = 0; i < 16; ++i) + { if (ours->getChildHash(i) != other->getChildHash(i)) { if (other->isEmptyBranch(i)) @@ -195,9 +210,12 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const if (!otherMap.walkBranch(iNode, nullptr, false, differences, maxCount)) return false; } - else // The two trees have different non-empty branches + else + { // The two trees have different non-empty branches nodeStack.push({descendThrow(ours, i), otherMap.descendThrow(other, i)}); + } } + } } else { @@ -306,9 +324,11 @@ SHAMap::walkMapParallel(std::vector& missingNodes, int maxMis if (nextNode) { if (nextNode->isInner()) + { nodeStack.push( intr_ptr::static_pointer_cast( nextNode)); + } } else { diff --git a/src/libxrpl/shamap/SHAMapInnerNode.cpp b/src/libxrpl/shamap/SHAMapInnerNode.cpp index 695e35c75d..599d343745 100644 --- a/src/libxrpl/shamap/SHAMapInnerNode.cpp +++ b/src/libxrpl/shamap/SHAMapInnerNode.cpp @@ -125,9 +125,13 @@ SHAMapInnerNode::makeFullInner(Slice data, SHAMapHash const& hash, bool hashVali ret->resizeChildArrays(ret->getBranchCount()); if (hashValid) + { ret->hash_ = hash; + } else + { ret->updateHash(); + } return ret; } @@ -253,9 +257,11 @@ SHAMapInnerNode::setChild(int m, intr_ptr::SharedPtr child) auto const dstIsBranch = [&] { if (child) + { return isBranch_ | (1u << m); - else - return isBranch_ & ~(1u << m); + } + + return isBranch_ & ~(1u << m); }(); auto const dstToAllocate = popcnt16(dstIsBranch); diff --git a/src/libxrpl/shamap/SHAMapLeafNode.cpp b/src/libxrpl/shamap/SHAMapLeafNode.cpp index 49dd99e935..3776de3a35 100644 --- a/src/libxrpl/shamap/SHAMapLeafNode.cpp +++ b/src/libxrpl/shamap/SHAMapLeafNode.cpp @@ -51,13 +51,21 @@ SHAMapLeafNode::getString(SHAMapNodeID const& id) const auto const type = getType(); if (type == SHAMapNodeType::tnTRANSACTION_NM) + { ret += ",txn\n"; + } else if (type == SHAMapNodeType::tnTRANSACTION_MD) + { ret += ",txn+md\n"; + } else if (type == SHAMapNodeType::tnACCOUNT_STATE) + { ret += ",as\n"; + } else + { ret += ",leaf\n"; + } ret += " Tag="; ret += to_string(item_->key()); diff --git a/src/libxrpl/shamap/SHAMapNodeID.cpp b/src/libxrpl/shamap/SHAMapNodeID.cpp index f7cc80e250..6536e628ef 100644 --- a/src/libxrpl/shamap/SHAMapNodeID.cpp +++ b/src/libxrpl/shamap/SHAMapNodeID.cpp @@ -107,9 +107,13 @@ selectBranch(SHAMapNodeID const& id, uint256 const& hash) auto branch = static_cast(*(hash.begin() + (depth / 2))); if (depth & 1) + { branch &= 0xf; + } else + { branch >>= 4; + } XRPL_ASSERT(branch < SHAMap::branchFactor, "xrpl::selectBranch : maximum result"); return branch; diff --git a/src/libxrpl/shamap/SHAMapSync.cpp b/src/libxrpl/shamap/SHAMapSync.cpp index 948d972c18..c6e4c3dcb0 100644 --- a/src/libxrpl/shamap/SHAMapSync.cpp +++ b/src/libxrpl/shamap/SHAMapSync.cpp @@ -46,7 +46,9 @@ SHAMap::visitNodes(std::function const& function) const return; if (child->isLeaf()) + { ++pos; + } else { // If there are no more children, don't push this node @@ -164,7 +166,7 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se) auto const& childHash = node->getChildHash(branch); - if (mn.missingHashes_.count(childHash) != 0) + if (mn.missingHashes_.contains(childHash)) { // we already know this child node is missing fullBelow = false; @@ -358,8 +360,10 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) { // Recheck nodes we could not finish before for (auto const& [innerNode, nodeId] : mn.resumes_) + { if (!innerNode->isFullBelow(mn.generation_)) mn.stack_.push(std::make_tuple(innerNode, nodeId, rand_int(255), 0, true)); + } mn.resumes_.clear(); } @@ -644,7 +648,7 @@ SHAMap::deepCompare(SHAMap& other) const JLOG(journal_.info()) << "unable to fetch node"; return false; } - else if (otherNode->getHash() != node->getHash()) + if (otherNode->getHash() != node->getHash()) { JLOG(journal_.warn()) << "node hash mismatch"; return false; diff --git a/src/libxrpl/tx/Transactor.cpp b/src/libxrpl/tx/Transactor.cpp index ec8e6aae2f..ff42441e2f 100644 --- a/src/libxrpl/tx/Transactor.cpp +++ b/src/libxrpl/tx/Transactor.cpp @@ -191,9 +191,11 @@ NotTEC Transactor::preflight2(PreflightContext const& ctx) { if (auto const ret = detail::preflightCheckSimulateKeys(ctx.flags, ctx.tx, ctx.j)) + { // Skips following checks if the transaction is being simulated, // regardless of success or failure return *ret; + } // It should be impossible for the InnerBatchTxn flag to be set without // featureBatch being enabled @@ -547,9 +549,13 @@ Transactor::ticketDelete( if (auto ticketCount = (*sleAccount)[~sfTicketCount]) { if (*ticketCount == 1) + { sleAccount->makeFieldAbsent(sfTicketCount); + } else + { ticketCount = *ticketCount - 1; + } } else { @@ -623,10 +629,12 @@ Transactor::checkSign( auto const sle = view.read(keylet::account(idAccount)); if (view.rules().enabled(featureLendingProtocol) && isPseudoAccount(sle)) + { // Pseudo-accounts can't sign transactions. This check is gated on // the Lending Protocol amendment because that's the project it was // added under, and it doesn't justify another amendment return tefBAD_AUTH; + } } auto const pkSigner = sigObject.getFieldVL(sfSigningPubKey); diff --git a/src/libxrpl/tx/apply.cpp b/src/libxrpl/tx/apply.cpp index caf42e9326..8fd898366e 100644 --- a/src/libxrpl/tx/apply.cpp +++ b/src/libxrpl/tx/apply.cpp @@ -50,8 +50,10 @@ checkValidity(HashRouter& router, STTx const& tx, Rules const& rules) } if (any(flags & SF_SIGBAD)) + { // Signature is known bad return {Validity::SigBad, "Transaction has bad signature."}; + } if (!any(flags & SF_SIGGOOD)) { @@ -66,14 +68,18 @@ checkValidity(HashRouter& router, STTx const& tx, Rules const& rules) // Signature is now known good if (any(flags & SF_LOCALBAD)) + { // ...but the local checks // are known bad. return {Validity::SigGoodOnly, "Local checks failed."}; + } if (any(flags & SF_LOCALGOOD)) + { // ...and the local checks // are known good. return {Validity::Valid, ""}; + } // Do the local checks std::string reason; @@ -189,7 +195,9 @@ applyBatchTransactions( break; } else if (mode & tfOnlyOne) + { break; + } } return applied != 0; diff --git a/src/libxrpl/tx/applySteps.cpp b/src/libxrpl/tx/applySteps.cpp index 0c8c538a11..6c6b3f8c98 100644 --- a/src/libxrpl/tx/applySteps.cpp +++ b/src/libxrpl/tx/applySteps.cpp @@ -344,6 +344,7 @@ preclaim(PreflightResult const& preflightResult, ServiceRegistry& registry, Open { auto secondFlight = [&]() { if (preflightResult.parentBatchId) + { return preflight( registry, view.rules(), @@ -351,6 +352,7 @@ preclaim(PreflightResult const& preflightResult, ServiceRegistry& registry, Open preflightResult.tx, preflightResult.flags, preflightResult.j); + } return preflight( registry, diff --git a/src/libxrpl/tx/invariants/AMMInvariant.cpp b/src/libxrpl/tx/invariants/AMMInvariant.cpp index 4d3c63cf4e..b64be6192b 100644 --- a/src/libxrpl/tx/invariants/AMMInvariant.cpp +++ b/src/libxrpl/tx/invariants/AMMInvariant.cpp @@ -55,8 +55,10 @@ validBalances( bool const positive = amount > beast::zero && amount2 > beast::zero && lptAMMBalance > beast::zero; if (zeroAllowed == ValidAMM::ZeroAllowed::Yes) + { return positive || (amount == beast::zero && amount2 == beast::zero && lptAMMBalance == beast::zero); + } return positive; } @@ -236,7 +238,9 @@ ValidAMM::finalizeDeposit( // LCOV_EXCL_STOP } else if (!generalInvariant(tx, view, ZeroAllowed::No, j) && enforce) + { return false; + } return true; } diff --git a/src/libxrpl/tx/invariants/FreezeInvariant.cpp b/src/libxrpl/tx/invariants/FreezeInvariant.cpp index 858c4cdcb8..f38d260782 100644 --- a/src/libxrpl/tx/invariants/FreezeInvariant.cpp +++ b/src/libxrpl/tx/invariants/FreezeInvariant.cpp @@ -157,9 +157,13 @@ TransfersNotFrozen::recordBalance(Issue const& issue, BalanceChange change) "balance sign."); auto& changes = balanceChanges_[issue]; if (change.balanceChangeSign < 0) + { changes.senders.emplace_back(std::move(change)); + } else + { changes.receivers.emplace_back(std::move(change)); + } } void diff --git a/src/libxrpl/tx/invariants/InvariantCheck.cpp b/src/libxrpl/tx/invariants/InvariantCheck.cpp index babeba9281..00580b2548 100644 --- a/src/libxrpl/tx/invariants/InvariantCheck.cpp +++ b/src/libxrpl/tx/invariants/InvariantCheck.cpp @@ -147,7 +147,7 @@ XRPNotCreated::finalize( TER const, XRPAmount const fee, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { // The net change should never be positive, as this would mean that the // transaction created XRP out of thin air. That's not possible. @@ -207,7 +207,7 @@ XRPBalanceChecks::finalize( TER const, XRPAmount const, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { if (bad_) { @@ -251,7 +251,7 @@ NoBadOffers::finalize( TER const, XRPAmount const, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { if (bad_) { @@ -344,7 +344,7 @@ NoZeroEscrow::finalize( TER const, XRPAmount const, ReadView const& rv, - beast::Journal const& j) + beast::Journal const& j) const { if (bad_) { @@ -373,7 +373,7 @@ AccountRootsNotDeleted::finalize( TER const result, XRPAmount const, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { // AMM account root can be deleted as the result of AMM withdraw/delete // transaction when the total AMM LP Tokens balance goes to 0. @@ -385,8 +385,10 @@ AccountRootsNotDeleted::finalize( return true; if (accountsDeleted_ == 0) + { JLOG(j.fatal()) << "Invariant failed: account deletion " "succeeded without deleting an account"; + } else JLOG(j.fatal()) << "Invariant failed: account deletion " "succeeded but deleted multiple accounts!"; @@ -565,7 +567,7 @@ LedgerEntryTypesMatch::finalize( TER const, XRPAmount const, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { if ((!typeMismatch_) && (!invalidTypeAdded_)) return true; @@ -607,7 +609,7 @@ NoXRPTrustLines::finalize( TER const, XRPAmount const, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { if (!xrpTrustLine_) return true; @@ -643,7 +645,7 @@ NoDeepFreezeTrustLinesWithoutFreeze::finalize( TER const, XRPAmount const, ReadView const&, - beast::Journal const& j) + beast::Journal const& j) const { if (!deepFreezeWithoutFreeze_) return true; @@ -676,7 +678,7 @@ ValidNewAccountRoot::finalize( TER const result, XRPAmount const, ReadView const& view, - beast::Journal const& j) + beast::Journal const& j) const { if (accountsCreated_ == 0) return true; @@ -751,7 +753,7 @@ ValidClawback::finalize( TER const result, XRPAmount const, ReadView const& view, - beast::Journal const& j) + beast::Journal const& j) const { if (tx.getTxnType() != ttCLAWBACK) return true; @@ -814,8 +816,10 @@ ValidPseudoAccounts::visitEntry( std::shared_ptr const& after) { if (isDelete) + { // Deletion is ignored return; + } if (after && after->getType() == ltACCOUNT_ROOT) { @@ -903,8 +907,10 @@ NoModifiedUnmodifiableFields::visitEntry( std::shared_ptr const& after) { if (isDelete || !before) + { // Creation and deletion are ignored return; + } changedEntries_.emplace(before, after); } diff --git a/src/libxrpl/tx/invariants/MPTInvariant.cpp b/src/libxrpl/tx/invariants/MPTInvariant.cpp index 56e0b54e7e..a3a5bf897d 100644 --- a/src/libxrpl/tx/invariants/MPTInvariant.cpp +++ b/src/libxrpl/tx/invariants/MPTInvariant.cpp @@ -19,15 +19,21 @@ ValidMPTIssuance::visitEntry( if (after && after->getType() == ltMPTOKEN_ISSUANCE) { if (isDelete) + { mptIssuancesDeleted_++; + } else if (!before) + { mptIssuancesCreated_++; + } } if (after && after->getType() == ltMPTOKEN) { if (isDelete) + { mptokensDeleted_++; + } else if (!before) { mptokensCreated_++; @@ -44,7 +50,7 @@ ValidMPTIssuance::finalize( TER const result, XRPAmount const _fee, ReadView const& view, - beast::Journal const& j) + beast::Journal const& j) const { if (isTesSuccess(result)) { @@ -122,26 +128,25 @@ ValidMPTIssuance::finalize( "succeeded but created MPT issuances"; return false; } - else if (mptIssuancesDeleted_ > 0) + if (mptIssuancesDeleted_ > 0) { JLOG(j.fatal()) << "Invariant failed: MPT authorize " "succeeded but deleted issuances"; return false; } - else if (lendingProtocolEnabled && mptokensCreated_ + mptokensDeleted_ > 1) + if (lendingProtocolEnabled && mptokensCreated_ + mptokensDeleted_ > 1) { JLOG(j.fatal()) << "Invariant failed: MPT authorize succeeded " "but created/deleted bad number mptokens"; return false; } - else if (submittedByIssuer && (mptokensCreated_ > 0 || mptokensDeleted_ > 0)) + if (submittedByIssuer && (mptokensCreated_ > 0 || mptokensDeleted_ > 0)) { JLOG(j.fatal()) << "Invariant failed: MPT authorize submitted by issuer " "succeeded but created/deleted mptokens"; return false; } - else if ( - !submittedByIssuer && hasPrivilege(tx, mustAuthorizeMPT) && + if (!submittedByIssuer && hasPrivilege(tx, mustAuthorizeMPT) && (mptokensCreated_ + mptokensDeleted_ != 1)) { // if the holder submitted this tx, then a mptoken must be diff --git a/src/libxrpl/tx/invariants/NFTInvariant.cpp b/src/libxrpl/tx/invariants/NFTInvariant.cpp index 7077625b60..cf00dc9290 100644 --- a/src/libxrpl/tx/invariants/NFTInvariant.cpp +++ b/src/libxrpl/tx/invariants/NFTInvariant.cpp @@ -120,7 +120,7 @@ ValidNFTokenPage::finalize( TER const result, XRPAmount const, ReadView const& view, - beast::Journal const& j) + beast::Journal const& j) const { if (badLink_) { @@ -196,7 +196,7 @@ NFTokenCountTracking::finalize( TER const result, XRPAmount const, ReadView const& view, - beast::Journal const& j) + beast::Journal const& j) const { if (!hasPrivilege(tx, changeNFTCounts)) { diff --git a/src/libxrpl/tx/invariants/PermissionedDEXInvariant.cpp b/src/libxrpl/tx/invariants/PermissionedDEXInvariant.cpp index e12312ad0f..e932a6ba09 100644 --- a/src/libxrpl/tx/invariants/PermissionedDEXInvariant.cpp +++ b/src/libxrpl/tx/invariants/PermissionedDEXInvariant.cpp @@ -24,9 +24,13 @@ ValidPermissionedDEX::visitEntry( if (after && after->getType() == ltOFFER) { if (after->isFieldPresent(sfDomainID)) + { domains_.insert(after->getFieldH256(sfDomainID)); + } else + { regularOffers_ = true; + } // if a hybrid offer is missing domain or additional book, there's // something wrong diff --git a/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp b/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp index 541be69623..d4cbe81f9b 100644 --- a/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp +++ b/src/libxrpl/tx/invariants/PermissionedDomainInvariant.cpp @@ -90,9 +90,10 @@ ValidPermissionedDomain::finalize( { // No permissioned domains should be affected if the transaction failed if (!isTesSuccess(result)) - // If nothing changed, all is good. If there were changes, that's - // bad. + { + // If nothing changed, all is good. If there were changes, that's bad. return sleStatus_.empty(); + } if (sleStatus_.size() > 1) { diff --git a/src/libxrpl/tx/invariants/VaultInvariant.cpp b/src/libxrpl/tx/invariants/VaultInvariant.cpp index c3db3a563a..e955e00b50 100644 --- a/src/libxrpl/tx/invariants/VaultInvariant.cpp +++ b/src/libxrpl/tx/invariants/VaultInvariant.cpp @@ -157,7 +157,7 @@ ValidVault::finalize( return true; // Not a vault operation } - else if (!(hasPrivilege(tx, mustModifyVault) || hasPrivilege(tx, mayModifyVault))) + if (!(hasPrivilege(tx, mustModifyVault) || hasPrivilege(tx, mayModifyVault))) { JLOG(j.fatal()) << // "Invariant failed: vault updated by a wrong transaction type"; @@ -239,7 +239,7 @@ ValidVault::finalize( return result; } - else if (txnType == ttVAULT_DELETE) + if (txnType == ttVAULT_DELETE) { JLOG(j.fatal()) << "Invariant failed: vault deletion succeeded without " "deleting a vault"; diff --git a/src/libxrpl/tx/paths/Flow.cpp b/src/libxrpl/tx/paths/Flow.cpp index c27eb54cbe..fc33585179 100644 --- a/src/libxrpl/tx/paths/Flow.cpp +++ b/src/libxrpl/tx/paths/Flow.cpp @@ -16,9 +16,13 @@ finishFlow(PaymentSandbox& sb, Issue const& srcIssue, Issue const& dstIssue, Flo { path::RippleCalc::Output result; if (isTesSuccess(f.ter)) + { f.sandbox->apply(sb); + } else + { result.removableOffers = std::move(f.removableOffers); + } result.setResult(f.ter); result.actualAmountIn = toSTAmount(f.in, srcIssue); diff --git a/src/libxrpl/tx/paths/OfferStream.cpp b/src/libxrpl/tx/paths/OfferStream.cpp index 596ae36b96..b406c27298 100644 --- a/src/libxrpl/tx/paths/OfferStream.cpp +++ b/src/libxrpl/tx/paths/OfferStream.cpp @@ -95,8 +95,10 @@ accountFundsHelper( beast::Journal j) { if (issue.account == id) + { // self funded return amtDefault; + } return toAmount( accountHolds(view, id, issue.currency, issue.account, freezeHandling, j)); diff --git a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp b/src/libxrpl/tx/transactors/account/DeleteAccount.cpp index 639e83c7e6..a70cc24549 100644 --- a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp +++ b/src/libxrpl/tx/transactors/account/DeleteAccount.cpp @@ -30,8 +30,10 @@ NotTEC DeleteAccount::preflight(PreflightContext const& ctx) { if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) + { // An account cannot be deleted and give itself the resulting XRP. return temDST_IS_SRC; + } if (auto const err = credentials::checkFields(ctx.tx, ctx.j); !isTesSuccess(err)) return err; diff --git a/src/libxrpl/tx/transactors/account/SetAccount.cpp b/src/libxrpl/tx/transactors/account/SetAccount.cpp index 032b4727ad..9bb92c2ea5 100644 --- a/src/libxrpl/tx/transactors/account/SetAccount.cpp +++ b/src/libxrpl/tx/transactors/account/SetAccount.cpp @@ -126,7 +126,7 @@ SetAccount::preflight(PreflightContext const& ctx) if (auto const mk = tx[~sfMessageKey]) { - if (mk->size() && !publicKeyType({mk->data(), mk->size()})) + if (!mk->empty() && !publicKeyType({mk->data(), mk->size()})) { JLOG(j.trace()) << "Invalid message key specified."; return telBAD_PUBLIC_KEY; @@ -565,32 +565,52 @@ SetAccount::doApply() sle->makeFieldAbsent(sfNFTokenMinter); if (uSetFlag == asfDisallowIncomingNFTokenOffer) + { uFlagsOut |= lsfDisallowIncomingNFTokenOffer; + } else if (uClearFlag == asfDisallowIncomingNFTokenOffer) + { uFlagsOut &= ~lsfDisallowIncomingNFTokenOffer; + } if (uSetFlag == asfDisallowIncomingCheck) + { uFlagsOut |= lsfDisallowIncomingCheck; + } else if (uClearFlag == asfDisallowIncomingCheck) + { uFlagsOut &= ~lsfDisallowIncomingCheck; + } if (uSetFlag == asfDisallowIncomingPayChan) + { uFlagsOut |= lsfDisallowIncomingPayChan; + } else if (uClearFlag == asfDisallowIncomingPayChan) + { uFlagsOut &= ~lsfDisallowIncomingPayChan; + } if (uSetFlag == asfDisallowIncomingTrustline) + { uFlagsOut |= lsfDisallowIncomingTrustline; + } else if (uClearFlag == asfDisallowIncomingTrustline) + { uFlagsOut &= ~lsfDisallowIncomingTrustline; + } // Set or clear flags for disallowing escrow if (ctx_.view().rules().enabled(featureTokenEscrow)) { if (uSetFlag == asfAllowTrustLineLocking) + { uFlagsOut |= lsfAllowTrustLineLocking; + } else if (uClearFlag == asfAllowTrustLineLocking) + { uFlagsOut &= ~lsfAllowTrustLineLocking; + } } // Set flag for clawback diff --git a/src/libxrpl/tx/transactors/account/SetSignerList.cpp b/src/libxrpl/tx/transactors/account/SetSignerList.cpp index 2a807febd3..54fe91aaa6 100644 --- a/src/libxrpl/tx/transactors/account/SetSignerList.cpp +++ b/src/libxrpl/tx/transactors/account/SetSignerList.cpp @@ -124,7 +124,7 @@ SetSignerList::preCompute() signers_ = std::get<2>(result); do_ = std::get<3>(result); - return Transactor::preCompute(); + Transactor::preCompute(); } // The return type is signed so it is compatible with the 3rd argument diff --git a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp index b0c1d657dd..2e274f138d 100644 --- a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp +++ b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp @@ -1027,8 +1027,10 @@ applyCreateAccountAttestations( XChainCreateAccountAttestations curAtts = [&] { if (sleClaimID) + { return XChainCreateAccountAttestations{ sleClaimID->getFieldArray(sfXChainCreateAccountAttestations)}; + } return XChainCreateAccountAttestations{}; }(); @@ -1203,8 +1205,10 @@ attestationDoApply(ApplyContext& ctx) { auto const att = toClaim(ctx.tx); if (!att) + { // Should already be checked in preflight return tecINTERNAL; // LCOV_EXCL_LINE + } STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; @@ -1233,11 +1237,17 @@ attestationDoApply(ApplyContext& ctx) STXChainBridge::ChainType dstChain = STXChainBridge::ChainType::locking; { if (thisDoor == bridgeSpec.lockingChainDoor()) + { dstChain = STXChainBridge::ChainType::locking; + } else if (thisDoor == bridgeSpec.issuingChainDoor()) + { dstChain = STXChainBridge::ChainType::issuing; + } else + { return Unexpected(tecINTERNAL); + } } STXChainBridge::ChainType const srcChain = STXChainBridge::otherChain(dstChain); @@ -1598,11 +1608,17 @@ XChainClaim::preclaim(PreclaimContext const& ctx) bool isLockingChain = false; { if (thisDoor == bridgeSpec.lockingChainDoor()) + { isLockingChain = true; + } else if (thisDoor == bridgeSpec.issuingChainDoor()) + { isLockingChain = false; + } else + { return tecINTERNAL; // LCOV_EXCL_LINE + } } { @@ -1631,9 +1647,13 @@ XChainClaim::preclaim(PreclaimContext const& ctx) auto const otherChainAmount = [&]() -> STAmount { STAmount r(thisChainAmount); if (isLockingChain) + { r.setIssue(bridgeSpec.issuingChainIssue()); + } else + { r.setIssue(bridgeSpec.lockingChainIssue()); + } return r; }(); @@ -1696,11 +1716,17 @@ XChainClaim::doApply() STXChainBridge::ChainType dstChain = STXChainBridge::ChainType::locking; { if (thisDoor == bridgeSpec.lockingChainDoor()) + { dstChain = STXChainBridge::ChainType::locking; + } else if (thisDoor == bridgeSpec.issuingChainDoor()) + { dstChain = STXChainBridge::ChainType::issuing; + } else + { return Unexpected(tecINTERNAL); + } } STXChainBridge::ChainType const srcChain = STXChainBridge::otherChain(dstChain); @@ -1823,11 +1849,17 @@ XChainCommit::preclaim(PreclaimContext const& ctx) bool isLockingChain = false; { if (thisDoor == bridgeSpec.lockingChainDoor()) + { isLockingChain = true; + } else if (thisDoor == bridgeSpec.issuingChainDoor()) + { isLockingChain = false; + } else + { return tecINTERNAL; // LCOV_EXCL_LINE + } } if (isLockingChain) @@ -2095,11 +2127,17 @@ XChainCreateAccountCommit::preclaim(PreclaimContext const& ctx) STXChainBridge::ChainType srcChain = STXChainBridge::ChainType::locking; { if (thisDoor == bridgeSpec.lockingChainDoor()) + { srcChain = STXChainBridge::ChainType::locking; + } else if (thisDoor == bridgeSpec.issuingChainDoor()) + { srcChain = STXChainBridge::ChainType::issuing; + } else + { return tecINTERNAL; // LCOV_EXCL_LINE + } } STXChainBridge::ChainType const dstChain = STXChainBridge::otherChain(srcChain); diff --git a/src/libxrpl/tx/transactors/check/CashCheck.cpp b/src/libxrpl/tx/transactors/check/CashCheck.cpp index 35368836a3..cba945cc82 100644 --- a/src/libxrpl/tx/transactors/check/CashCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CashCheck.cpp @@ -265,8 +265,10 @@ CashCheck::doApply() } if (optDeliverMin) + { // Set the DeliveredAmount metadata. ctx_.deliver(xrpDeliver); + } // The source account has enough XRP so make the ledger change. if (TER const ter{transferXRP(psb, srcId, account_, xrpDeliver, viewJ)}; diff --git a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp index 58f68b628a..2a9aafc6be 100644 --- a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp +++ b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp @@ -66,8 +66,10 @@ DelegateSet::doApply() { auto const& permissions = ctx_.tx.getFieldArray(sfPermissions); if (permissions.empty()) + { // if permissions array is empty, delete the ledger object. return deleteDelegate(view(), sle, account_, j_); + } sle->setFieldArray(sfPermissions, permissions); ctx_.view().update(sle); diff --git a/src/libxrpl/tx/transactors/dex/AMMBid.cpp b/src/libxrpl/tx/transactors/dex/AMMBid.cpp index cc255edcf2..a1ace702dc 100644 --- a/src/libxrpl/tx/transactors/dex/AMMBid.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMBid.cpp @@ -46,13 +46,13 @@ AMMBid::preflight(PreflightContext const& ctx) if (ctx.tx.isFieldPresent(sfAuthAccounts)) { - if (auto const authAccounts = ctx.tx.getFieldArray(sfAuthAccounts); - authAccounts.size() > AUCTION_SLOT_MAX_AUTH_ACCOUNTS) + auto const authAccounts = ctx.tx.getFieldArray(sfAuthAccounts); + if (authAccounts.size() > AUCTION_SLOT_MAX_AUTH_ACCOUNTS) { JLOG(ctx.j.debug()) << "AMM Bid: Invalid number of AuthAccounts."; return temMALFORMED; } - else if (ctx.rules.enabled(fixAMMv1_3)) + if (ctx.rules.enabled(fixAMMv1_3)) { AccountID account = ctx.tx[sfAccount]; std::set unique; @@ -193,14 +193,22 @@ applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jour auctionSlot.setAccountID(sfAccount, account_); auctionSlot.setFieldU32(sfExpiration, current + TOTAL_TIME_SLOT_SECS); if (fee != 0) + { auctionSlot.setFieldU16(sfDiscountedFee, fee); + } else if (auctionSlot.isFieldPresent(sfDiscountedFee)) + { auctionSlot.makeFieldAbsent(sfDiscountedFee); + } auctionSlot.setFieldAmount(sfPrice, toSTAmount(lpTokens.issue(), minPrice)); if (ctx_.tx.isFieldPresent(sfAuthAccounts)) + { auctionSlot.setFieldArray(sfAuthAccounts, ctx_.tx.getFieldArray(sfAuthAccounts)); + } else + { auctionSlot.makeFieldAbsent(sfAuthAccounts); + } // Burn the remaining bid amount auto const saBurn = adjustLPTokens(lptAMMBalance, toSTAmount(lptAMMBalance.issue(), burn), IsDeposit::No); @@ -245,7 +253,7 @@ applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jour { return std::max(computedPrice, Number(*bidMin)); } - else if (bidMax) + if (bidMax) { if (computedPrice <= *bidMax) return computedPrice; @@ -253,23 +261,30 @@ applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jour << "AMM Bid: not in range " << computedPrice << " " << *bidMax; return std::nullopt; } - else - return computedPrice; + + return computedPrice; }(); if (!payPrice) + { return Unexpected(tecAMM_FAILED); - else if (payPrice > lpTokens) + } + if (payPrice > lpTokens) + { return Unexpected(tecAMM_INVALID_TOKENS); + } return *payPrice; }; // No one owns the slot or expired slot. if (auto const acct = auctionSlot[~sfAccount]; !acct || !validOwner(*acct)) { - if (auto const payPrice = getPayPrice(minSlotPrice); !payPrice) + auto const payPrice = getPayPrice(minSlotPrice); + if (!payPrice) + { return {payPrice.error(), false}; - else - res = updateSlot(discountedFee, *payPrice, *payPrice); + } + + res = updateSlot(discountedFee, *payPrice, *payPrice); } else { diff --git a/src/libxrpl/tx/transactors/dex/AMMClawback.cpp b/src/libxrpl/tx/transactors/dex/AMMClawback.cpp index 20645238c5..a5fda15033 100644 --- a/src/libxrpl/tx/transactors/dex/AMMClawback.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMClawback.cpp @@ -156,6 +156,7 @@ AMMClawback::applyGuts(Sandbox& sb) return tecAMM_BALANCE; if (!clawAmount) + { // Because we are doing a two-asset withdrawal, // tfee is actually not used, so pass tfee as 0. std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) = @@ -174,7 +175,9 @@ AMMClawback::applyGuts(Sandbox& sb) WithdrawAll::Yes, preFeeBalance_, ctx_.journal); + } else + { std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) = equalWithdrawMatchingOneAmount( sb, @@ -186,6 +189,7 @@ AMMClawback::applyGuts(Sandbox& sb) lptAMMBalance, holdLPtokens, *clawAmount); + } if (!isTesSuccess(result)) return result; // LCOV_EXCL_LINE @@ -235,6 +239,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( auto const lpTokensWithdraw = toSTAmount(lptAMMBalance.issue(), lptAMMBalance * frac); if (lpTokensWithdraw > holdLPtokens) + { // if lptoken balance less than what the issuer intended to clawback, // clawback all the tokens. Because we are doing a two-asset withdrawal, // tfee is actually not used, so pass tfee as 0. @@ -253,6 +258,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( WithdrawAll::Yes, preFeeBalance_, ctx_.journal); + } auto const& rules = sb.rules(); if (rules.enabled(fixAMMClawbackRounding)) diff --git a/src/libxrpl/tx/transactors/dex/AMMCreate.cpp b/src/libxrpl/tx/transactors/dex/AMMCreate.cpp index 38eea436dd..86128ed1cd 100644 --- a/src/libxrpl/tx/transactors/dex/AMMCreate.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMCreate.cpp @@ -163,9 +163,10 @@ AMMCreate::preclaim(PreclaimContext const& ctx) auto clawbackDisabled = [&](Issue const& issue) -> TER { if (isXRP(issue)) return tesSUCCESS; - if (auto const sle = ctx.view.read(keylet::account(issue.account)); !sle) + auto const sle = ctx.view.read(keylet::account(issue.account)); + if (!sle) return tecINTERNAL; // LCOV_EXCL_LINE - else if (sle->getFlags() & lsfAllowTrustLineClawback) + if (sle->getFlags() & lsfAllowTrustLineClawback) return tecNO_PERMISSION; return tesSUCCESS; }; @@ -244,15 +245,15 @@ applyCreate(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::J // Set AMM flag on AMM trustline if (!isXRP(amount)) { - if (SLE::pointer sleRippleState = sb.peek(keylet::line(accountId, amount.issue())); - !sleRippleState) - return tecINTERNAL; // LCOV_EXCL_LINE - else + SLE::pointer sleRippleState = sb.peek(keylet::line(accountId, amount.issue())); + if (!sleRippleState) { - auto const flags = sleRippleState->getFlags(); - sleRippleState->setFieldU32(sfFlags, flags | lsfAMMNode); - sb.update(sleRippleState); + return tecINTERNAL; // LCOV_EXCL_LINE } + + auto const flags = sleRippleState->getFlags(); + sleRippleState->setFieldU32(sfFlags, flags | lsfAMMNode); + sb.update(sleRippleState); } return tesSUCCESS; }; diff --git a/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp b/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp index c83b1f2245..9b78b9e2bf 100644 --- a/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp @@ -356,6 +356,7 @@ AMMDeposit::applyGuts(Sandbox& sb) &lptAMMBalance = lptAMMBalance]() -> std::pair { if (subTxType & tfTwoAsset) + { return equalDepositLimit( sb, ammAccountID, @@ -366,16 +367,24 @@ AMMDeposit::applyGuts(Sandbox& sb) *amount2, lpTokensDeposit, tfee); + } if (subTxType & tfOneAssetLPToken) + { return singleDepositTokens( sb, ammAccountID, amountBalance, *amount, lptAMMBalance, *lpTokensDeposit, tfee); + } if (subTxType & tfLimitLPToken) + { return singleDepositEPrice( sb, ammAccountID, amountBalance, *amount, lptAMMBalance, *ePrice, tfee); + } if (subTxType & tfSingleAsset) + { return singleDeposit( sb, ammAccountID, amountBalance, lptAMMBalance, *amount, lpTokensDeposit, tfee); + } if (subTxType & tfLPToken) + { return equalDepositTokens( sb, ammAccountID, @@ -386,9 +395,12 @@ AMMDeposit::applyGuts(Sandbox& sb) amount, amount2, tfee); + } if (subTxType & tfTwoAssetIfEmpty) + { return equalDepositInEmptyState( sb, ammAccountID, *amount, *amount2, lptAMMBalance.issue(), tfee); + } // should not happen. // LCOV_EXCL_START JLOG(j_.error()) << "AMM Deposit: invalid options."; @@ -462,7 +474,9 @@ AMMDeposit::deposit( depositAmount.issue(), FreezeHandling::fhIGNORE_FREEZE, ctx_.journal) >= depositAmount) + { return tesSUCCESS; + } return tecUNFUNDED_AMM; }; @@ -646,14 +660,17 @@ AMMDeposit::equalDepositLimit( if (tokensAdj == beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) + { return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE - else - return {tecAMM_INVALID_TOKENS, STAmount{}}; + } + + return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac); auto const amount2Deposit = getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::Yes); if (amount2Deposit <= amount2) + { return deposit( view, ammAccount, @@ -666,19 +683,23 @@ AMMDeposit::equalDepositLimit( std::nullopt, lpTokensDepositMin, tfee); + } frac = Number{amount2} / amount2Balance; tokensAdj = getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::Yes); if (tokensAdj == beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) + { return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE - else - return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE + } + + return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE } // factor in the adjusted tokens frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac); auto const amountDeposit = getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::Yes); if (amountDeposit <= amount) + { return deposit( view, ammAccount, @@ -691,6 +712,7 @@ AMMDeposit::equalDepositLimit( std::nullopt, lpTokensDepositMin, tfee); + } return {tecAMM_FAILED, STAmount{}}; } @@ -717,9 +739,11 @@ AMMDeposit::singleDeposit( if (tokens == beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) + { return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE - else - return {tecAMM_INVALID_TOKENS, STAmount{}}; + } + + return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens auto const [tokensAdj, amountDepositAdj] = @@ -820,9 +844,11 @@ AMMDeposit::singleDepositEPrice( if (tokens <= beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) + { return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE - else - return {tecAMM_INVALID_TOKENS, STAmount{}}; + } + + return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens auto const [tokensAdj, amountDepositAdj] = @@ -831,6 +857,7 @@ AMMDeposit::singleDepositEPrice( return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE auto const ep = Number{amountDepositAdj} / tokensAdj; if (ep <= ePrice) + { return deposit( view, ammAccount, @@ -843,6 +870,7 @@ AMMDeposit::singleDepositEPrice( std::nullopt, std::nullopt, tfee); + } } // LPTokens is asset out => E = b / t diff --git a/src/libxrpl/tx/transactors/dex/AMMHelpers.cpp b/src/libxrpl/tx/transactors/dex/AMMHelpers.cpp index 75aa51c9d4..20ffab52ca 100644 --- a/src/libxrpl/tx/transactors/dex/AMMHelpers.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMHelpers.cpp @@ -34,12 +34,10 @@ lpTokensOut( auto const t = lptAMMBalance * (r - c) / (1 + c); return toSTAmount(lptAMMBalance.issue(), t); } - else - { - // minimize tokens out - auto const frac = (r - c) / (1 + c); - return multiply(lptAMMBalance, frac, Number::downward); - } + + // minimize tokens out + auto const frac = (r - c) / (1 + c); + return multiply(lptAMMBalance, frac, Number::downward); } /* Equation 4 solves equation 3 for b: @@ -72,12 +70,10 @@ ammAssetIn( { return toSTAmount(asset1Balance.issue(), asset1Balance * solveQuadraticEq(a, b, c)); } - else - { - // maximize deposit - auto const frac = solveQuadraticEq(a, b, c); - return multiply(asset1Balance, frac, Number::upward); - } + + // maximize deposit + auto const frac = solveQuadraticEq(a, b, c); + return multiply(asset1Balance, frac, Number::upward); } /* Equation 7: @@ -99,12 +95,10 @@ lpTokensIn( auto const t = lptAMMBalance * (c - root2(c * c - 4 * fr)) / 2; return toSTAmount(lptAMMBalance.issue(), t); } - else - { - // maximize tokens in - auto const frac = (c - root2(c * c - 4 * fr)) / 2; - return multiply(lptAMMBalance, frac, Number::upward); - } + + // maximize tokens in + auto const frac = (c - root2(c * c - 4 * fr)) / 2; + return multiply(lptAMMBalance, frac, Number::upward); } /* Equation 8 solves equation 7 for b: @@ -131,12 +125,10 @@ ammAssetOut( auto const b = assetBalance * (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1); return toSTAmount(assetBalance.issue(), b); } - else - { - // minimize withdraw - auto const frac = (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1); - return multiply(assetBalance, frac, Number::downward); - } + + // minimize withdraw + auto const frac = (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1); + return multiply(assetBalance, frac, Number::downward); } Number @@ -194,29 +186,37 @@ adjustAmountsByLPTokens( auto const amountActual = toSTAmount(amount.issue(), fr * amount); auto const amount2Actual = toSTAmount(amount2->issue(), fr * *amount2); if (!ammRoundingEnabled) + { return std::make_tuple( amountActual < amount ? amountActual : amount, amount2Actual < amount2 ? amount2Actual : amount2, lpTokensActual); - else - return std::make_tuple(amountActual, amount2Actual, lpTokensActual); + } + + return std::make_tuple(amountActual, amount2Actual, lpTokensActual); } // Single trade auto const amountActual = [&]() { if (isDeposit == IsDeposit::Yes) + { return ammAssetIn(amountBalance, lptAMMBalance, lpTokensActual, tfee); - else if (!ammRoundingEnabled) + } + if (!ammRoundingEnabled) + { return ammAssetOut(amountBalance, lptAMMBalance, lpTokens, tfee); - else - return ammAssetOut(amountBalance, lptAMMBalance, lpTokensActual, tfee); + } + + return ammAssetOut(amountBalance, lptAMMBalance, lpTokensActual, tfee); }(); if (!ammRoundingEnabled) + { return amountActual < amount ? std::make_tuple(amountActual, std::nullopt, lpTokensActual) : std::make_tuple(amount, std::nullopt, lpTokensActual); - else - return std::make_tuple(amountActual, std::nullopt, lpTokensActual); + } + + return std::make_tuple(amountActual, std::nullopt, lpTokensActual); } XRPL_ASSERT( @@ -241,9 +241,11 @@ solveQuadraticEqSmallest(Number const& a, Number const& b, Number const& c) // use numerically stable citardauq formula for quadratic equation solution // https://people.csail.mit.edu/bkph/articles/Quadratics.pdf if (b > 0) + { return (2 * c) / (-b - root2(d)); - else - return (2 * c) / (-b + root2(d)); + } + + return (2 * c) / (-b + root2(d)); } STAmount diff --git a/src/libxrpl/tx/transactors/dex/AMMUtils.cpp b/src/libxrpl/tx/transactors/dex/AMMUtils.cpp index ed008ca75b..91891ce86f 100644 --- a/src/libxrpl/tx/transactors/dex/AMMUtils.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMUtils.cpp @@ -52,9 +52,13 @@ ammHolds( Issue checkIssue, char const* label) -> std::optional> { if (checkIssue == issue1) + { return std::make_optional(std::make_pair(issue1, issue2)); - else if (checkIssue == issue2) + } + if (checkIssue == issue2) + { return std::make_optional(std::make_pair(issue2, issue1)); + } // Unreachable unless AMM corrupted. // LCOV_EXCL_START JLOG(j.debug()) << "ammHolds: Invalid " << label << " " << checkIssue; @@ -65,7 +69,7 @@ ammHolds( { return singleIssue(*optIssue1, "optIssue1"); } - else if (optIssue2) + if (optIssue2) { // Cannot have Amount2 without Amount. return singleIssue(*optIssue2, "optIssue2"); // LCOV_EXCL_LINE @@ -165,8 +169,10 @@ getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account) if (auctionSlot.isFieldPresent(sfAuthAccounts)) { for (auto const& acct : auctionSlot.getFieldArray(sfAuthAccounts)) + { if (acct[~sfAccount] == account) return auctionSlot[sfDiscountedFee]; + } } } } @@ -323,13 +329,21 @@ initializeFeeAuctionVote( auctionSlot.setFieldAmount(sfPrice, STAmount{lptIssue, 0}); // Set the fee if (tfee != 0) + { ammSle->setFieldU16(sfTradingFee, tfee); + } else if (ammSle->isFieldPresent(sfTradingFee)) + { ammSle->makeFieldAbsent(sfTradingFee); // LCOV_EXCL_LINE + } if (auto const dfee = tfee / AUCTION_SLOT_DISCOUNTED_FEE_FRACTION) + { auctionSlot.setFieldU16(sfDiscountedFee, dfee); + } else if (auctionSlot.isFieldPresent(sfDiscountedFee)) + { auctionSlot.makeFieldAbsent(sfDiscountedFee); // LCOV_EXCL_LINE + } } Expected @@ -390,13 +404,19 @@ isOnlyLiquidityProvider(ReadView const& view, Issue const& ammIssue, AccountID c return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE } else if (++nIOUTrustLines > 2) + { return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE + } } // Another Liquidity Provider LPToken trustline else if (isLPTokenTrustline) + { return false; + } else if (++nIOUTrustLines > 2) + { return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE + } } auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext); if (uNodeNext == 0) @@ -417,9 +437,13 @@ verifyAndAdjustLPTokenBalance( std::shared_ptr& ammSle, AccountID const& account) { - if (auto const res = isOnlyLiquidityProvider(sb, lpTokens.issue(), account); !res) + auto const res = isOnlyLiquidityProvider(sb, lpTokens.issue(), account); + if (!res.has_value()) + { return Unexpected(res.error()); - else if (res.value()) + } + + if (res.value()) { if (withinRelativeDistance( lpTokens, ammSle->getFieldAmount(sfLPTokenBalance), Number{1, -3})) diff --git a/src/libxrpl/tx/transactors/dex/AMMVote.cpp b/src/libxrpl/tx/transactors/dex/AMMVote.cpp index d784b67f88..2096eca0f0 100644 --- a/src/libxrpl/tx/transactors/dex/AMMVote.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMVote.cpp @@ -35,15 +35,17 @@ AMMVote::preflight(PreflightContext const& ctx) TER AMMVote::preclaim(PreclaimContext const& ctx) { - if (auto const ammSle = ctx.view.read(keylet::amm(ctx.tx[sfAsset], ctx.tx[sfAsset2])); !ammSle) + auto const ammSle = ctx.view.read(keylet::amm(ctx.tx[sfAsset], ctx.tx[sfAsset2])); + if (!ammSle) { JLOG(ctx.j.debug()) << "AMM Vote: Invalid asset pair."; return terNO_AMM; } - else if (ammSle->getFieldAmount(sfLPTokenBalance) == beast::zero) + if (ammSle->getFieldAmount(sfLPTokenBalance) == beast::zero) + { return tecAMM_EMPTY; - else if ( - auto const lpTokensNew = ammLPHolds(ctx.view, *ammSle, ctx.tx[sfAccount], ctx.j); + } + if (auto const lpTokensNew = ammLPHolds(ctx.view, *ammSle, ctx.tx[sfAccount], ctx.j); lpTokensNew == beast::zero) { JLOG(ctx.j.debug()) << "AMM Vote: account is not LP."; @@ -134,16 +136,22 @@ applyVote(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jou num += feeNew * lpTokensNew; den += lpTokensNew; if (minPos) + { *(updatedVoteSlots.begin() + *minPos) = std::move(newEntry); + } else + { updatedVoteSlots.push_back(std::move(newEntry)); + } }; // Add new entry if the number of the vote entries // is less than Max. if (updatedVoteSlots.size() < VOTE_MAX_SLOTS) + { update(); - // Add the entry if the account has more tokens than - // the least token holder or same tokens and higher fee. + // Add the entry if the account has more tokens than + // the least token holder or same tokens and higher fee. + } else if (lpTokensNew > *minTokens || (lpTokensNew == *minTokens && feeNew > minFee)) { auto const entry = updatedVoteSlots.begin() + minPos; @@ -174,9 +182,13 @@ applyVote(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jou { auto& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot); if (auto const discountedFee = fee / AUCTION_SLOT_DISCOUNTED_FEE_FRACTION) + { auctionSlot.setFieldU16(sfDiscountedFee, discountedFee); + } else if (auctionSlot.isFieldPresent(sfDiscountedFee)) + { auctionSlot.makeFieldAbsent(sfDiscountedFee); + } } } else diff --git a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp index 8b0b75b317..f43367ac21 100644 --- a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp @@ -305,6 +305,7 @@ AMMWithdraw::applyGuts(Sandbox& sb) &lptAMMBalance = lptAMMBalance]() -> std::pair { if (subTxType & tfTwoAsset) + { return equalWithdrawLimit( sb, *ammSle, @@ -315,7 +316,9 @@ AMMWithdraw::applyGuts(Sandbox& sb) *amount, *amount2, tfee); + } if (subTxType & tfOneAssetLPToken || subTxType & tfOneAssetWithdrawAll) + { return singleWithdrawTokens( sb, *ammSle, @@ -325,12 +328,17 @@ AMMWithdraw::applyGuts(Sandbox& sb) *amount, *lpTokensWithdraw, tfee); + } if (subTxType & tfLimitLPToken) + { return singleWithdrawEPrice( sb, *ammSle, ammAccountID, amountBalance, lptAMMBalance, *amount, *ePrice, tfee); + } if (subTxType & tfSingleAsset) + { return singleWithdraw( sb, *ammSle, ammAccountID, amountBalance, lptAMMBalance, *amount, tfee); + } if (subTxType & tfLPToken || subTxType & tfWithdrawAll) { return equalWithdrawTokens( @@ -449,6 +457,7 @@ AMMWithdraw::withdraw( auto const [amountWithdrawActual, amount2WithdrawActual, lpTokensWithdrawActual] = [&]() -> std::tuple, STAmount> { if (withdrawAll == WithdrawAll::No) + { return adjustAmountsByLPTokens( amountBalance, amountWithdraw, @@ -457,6 +466,7 @@ AMMWithdraw::withdraw( lpTokensWithdraw, tfee, IsDeposit::No); + } return std::make_tuple(amountWithdraw, amount2Withdraw, lpTokensWithdraw); }(); @@ -649,8 +659,8 @@ AMMWithdraw::deleteAMMAccountIfEmpty( ter = deleteAMMAccount(sb, issue1, issue2, journal); if (!isTesSuccess(ter) && ter != tecINCOMPLETE) return {ter, false}; // LCOV_EXCL_LINE - else - updateBalance = (ter == tecINCOMPLETE); + + updateBalance = (ter == tecINCOMPLETE); } if (updateBalance) @@ -821,7 +831,9 @@ AMMWithdraw::equalWithdrawLimit( // LCOV_EXCL_STOP } else if (amountWithdraw > amount) + { return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE + } return withdraw( view, ammSle, @@ -857,9 +869,11 @@ AMMWithdraw::singleWithdraw( if (tokens == beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) + { return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE - else - return {tecAMM_INVALID_TOKENS, STAmount{}}; + } + + return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens auto const [tokensAdj, amountWithdrawAdj] = @@ -973,9 +987,11 @@ AMMWithdraw::singleWithdrawEPrice( if (tokensAdj <= beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) + { return {tecAMM_FAILED, STAmount{}}; - else - return {tecAMM_INVALID_TOKENS, STAmount{}}; + } + + return {tecAMM_INVALID_TOKENS, STAmount{}}; } auto amtNoRoundCb = [&] { return tokensAdj / ePrice; }; auto amtProdCb = [&] { return tokensAdj / ePrice; }; diff --git a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp b/src/libxrpl/tx/transactors/dex/CreateOffer.cpp index a620584c4e..58241803a9 100644 --- a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp +++ b/src/libxrpl/tx/transactors/dex/CreateOffer.cpp @@ -337,14 +337,18 @@ CreateOffer::flowCross( // specified. Since we don't know how much they might offer, // we allow delivery of the largest possible amount. if (deliver.native()) + { deliver = STAmount{STAmount::cMaxNative}; + } else + { // We can't use the maximum possible currency here because // there might be a gateway transfer rate to account for. // Since the transfer rate cannot exceed 200%, we use 1/2 // maxValue for our limit. deliver = STAmount{ takerAmount.out.issue(), STAmount::cMaxValue / 2, STAmount::cMaxOffset}; + } } // Call the payment engine's flow() to do the actual work. @@ -402,17 +406,21 @@ CreateOffer::flowCross( // gateway's transfer rate. STAmount nonGatewayAmountIn = result.actualAmountIn; if (gatewayXferRate.value != QUALITY_ONE) + { nonGatewayAmountIn = divideRound( result.actualAmountIn, gatewayXferRate, takerAmount.in.issue(), true); + } afterCross.in -= nonGatewayAmountIn; // It's possible that the divRound will cause our subtract // to go slightly negative. So limit afterCross.in to zero. if (afterCross.in < beast::zero) + { // We should verify that the difference *is* small, but // what is a good threshold to check? afterCross.in.clear(); + } afterCross.out = divRoundStrict(afterCross.in, rate, takerAmount.out.issue(), false); @@ -713,10 +721,12 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) { JLOG(j_.trace()) << "Immediate or cancel: offer canceled"; if (!crossed) + { // Any ImmediateOrCancel offer that transfers absolutely no funds // returns tecKILLED rather than tesSUCCESS. Motivation for the // change is here: https://github.com/ripple/rippled/issues/4115 return {tecKILLED, false}; + } return {tesSUCCESS, true}; } @@ -855,9 +865,13 @@ CreateOffer::doApply() auto const result = applyGuts(sb, sbCancel); if (result.second) + { sb.apply(ctx_.rawView()); + } else + { sbCancel.apply(ctx_.rawView()); + } return result.first; } diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp index 153366f167..61e27a7c38 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp @@ -150,7 +150,9 @@ EscrowCancel::doApply() // Transfer amount back to the owner if (isXRP(amount)) + { (*sle)[sfBalance] = (*sle)[sfBalance] + amount; + } else { if (!ctx_.view().rules().enabled(featureTokenEscrow)) diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp index bf3a6c7600..adeee09390 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp @@ -476,7 +476,9 @@ EscrowCreate::doApply() // Deduct owner's balance if (isXRP(amount)) + { (*sle)[sfBalance] = (*sle)[sfBalance] - amount; + } else { if (auto const ret = std::visit( diff --git a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp index d3167b95b9..680a20a077 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp @@ -81,9 +81,13 @@ EscrowFinish::preflightSigValidated(PreflightContext const& ctx) if (!any(flags & (SF_CF_INVALID | SF_CF_VALID))) { if (checkCondition(*fb, *cb)) + { router.setFlags(id, SF_CF_VALID); + } else + { router.setFlags(id, SF_CF_INVALID); + } } } @@ -246,9 +250,13 @@ EscrowFinish::doApply() return tecINTERNAL; if (checkCondition(*fb, *cb)) + { flags = SF_CF_VALID; + } else + { flags = SF_CF_INVALID; + } ctx_.registry.getHashRouter().setFlags(id, flags); // LCOV_EXCL_STOP @@ -315,7 +323,9 @@ EscrowFinish::doApply() STAmount const amount = slep->getFieldAmount(sfAmount); // Transfer amount to destination if (isXRP(amount)) + { (*sled)[sfBalance] = (*sled)[sfBalance] + amount; + } else { if (!ctx_.view().rules().enabled(featureTokenEscrow)) diff --git a/src/libxrpl/tx/transactors/lending/LendingHelpers.cpp b/src/libxrpl/tx/transactors/lending/LendingHelpers.cpp index d7162bbb0e..ad4cd8440d 100644 --- a/src/libxrpl/tx/transactors/lending/LendingHelpers.cpp +++ b/src/libxrpl/tx/transactors/lending/LendingHelpers.cpp @@ -856,9 +856,11 @@ computeFullPayment( << ", untrackedInterest: " << full.untrackedInterest; if (amount < full.totalDue) + { // If the payment is less than the full payment amount, it's not // sufficient to be a full payment. return Unexpected(tecINSUFFICIENT_PAYMENT); + } return full; } @@ -1635,24 +1637,26 @@ loanMakePayment( LoanState const roundedLoanState = constructLoanState( totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy); - if (auto const fullPaymentComponents = detail::computeFullPayment( - asset, - view, - principalOutstandingProxy, - managementFeeOutstandingProxy, - periodicPayment, - paymentRemainingProxy, - prevPaymentDateProxy, - startDate, - paymentInterval, - closeInterestRate, - loanScale, - roundedLoanState.interestDue, - periodicRate, - closePaymentFee, - amount, - managementFeeRate, - j)) + auto const fullPaymentComponents = detail::computeFullPayment( + asset, + view, + principalOutstandingProxy, + managementFeeOutstandingProxy, + periodicPayment, + paymentRemainingProxy, + prevPaymentDateProxy, + startDate, + paymentInterval, + closeInterestRate, + loanScale, + roundedLoanState.interestDue, + periodicRate, + closePaymentFee, + amount, + managementFeeRate, + j); + + if (fullPaymentComponents.has_value()) { return doPayment( *fullPaymentComponents, @@ -1664,11 +1668,14 @@ loanMakePayment( nextDueDateProxy, paymentInterval); } - else if (fullPaymentComponents.error()) + + if (fullPaymentComponents.error()) + { // error() will be the TER returned if a payment is not made. It // will only evaluate to true if it's unsuccessful. Otherwise, // tesSUCCESS means nothing was done, so continue. return Unexpected(fullPaymentComponents.error()); + } // LCOV_EXCL_START UNREACHABLE("xrpl::loanMakePayment : invalid full payment result"); @@ -1704,18 +1711,20 @@ loanMakePayment( TenthBips32 const lateInterestRate{loan->at(sfLateInterestRate)}; Number const latePaymentFee = loan->at(sfLatePaymentFee); - if (auto const latePaymentComponents = detail::computeLatePayment( - asset, - view, - principalOutstandingProxy, - nextDueDateProxy, - periodic, - lateInterestRate, - loanScale, - latePaymentFee, - amount, - managementFeeRate, - j)) + auto const latePaymentComponents = detail::computeLatePayment( + asset, + view, + principalOutstandingProxy, + nextDueDateProxy, + periodic, + lateInterestRate, + loanScale, + latePaymentFee, + amount, + managementFeeRate, + j); + + if (latePaymentComponents.has_value()) { return doPayment( *latePaymentComponents, @@ -1727,7 +1736,8 @@ loanMakePayment( nextDueDateProxy, paymentInterval); } - else if (latePaymentComponents.error()) + + if (latePaymentComponents.error()) { // error() will be the TER returned if a payment is not made. It // will only evaluate to true if it's unsuccessful. @@ -1858,13 +1868,17 @@ loanMakePayment( paymentRemainingProxy, managementFeeRate, j)) + { totalParts += *overResult; + } else if (overResult.error()) + { // error() will be the TER returned if a payment is not // made. It will only evaluate to true if it's unsuccessful. // Otherwise, tesSUCCESS means nothing was done, so // continue. return Unexpected(overResult.error()); + } } } diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp index 8513ae5999..4c55a7d33a 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverClawback.cpp @@ -118,14 +118,14 @@ determineAsset( { return amount.asset(); } - else if (holder == brokerPseudoAccountID) + if (holder == brokerPseudoAccountID) { // We want the asset to match the vault asset, so use the account as the // issuer return Issue{amount.getCurrency(), account}; } - else - return Unexpected(tecWRONG_ASSET); + + return Unexpected(tecWRONG_ASSET); } Expected diff --git a/src/libxrpl/tx/transactors/lending/LoanPay.cpp b/src/libxrpl/tx/transactors/lending/LoanPay.cpp index d894c56631..3543b7607f 100644 --- a/src/libxrpl/tx/transactors/lending/LoanPay.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanPay.cpp @@ -56,9 +56,11 @@ LoanPay::calculateBaseFee(ReadView const& view, STTx const& tx) auto const normalCost = Transactor::calculateBaseFee(view, tx); if (tx.isFlag(tfLoanFullPayment) || tx.isFlag(tfLoanLatePayment)) + { // The loan will be making one set of calculations for one full or late // payment return normalCost; + } // The fee is based on the potential number of payments, unless the loan is // being fully paid off. @@ -67,8 +69,10 @@ LoanPay::calculateBaseFee(ReadView const& view, STTx const& tx) auto const loanSle = view.read(keylet::loan(loanID)); if (!loanSle) + { // Let preclaim worry about the error for this return normalCost; + } if (loanSle->at(sfPaymentRemaining) <= loanPaymentsPerFeeIncrement) { @@ -78,24 +82,32 @@ LoanPay::calculateBaseFee(ReadView const& view, STTx const& tx) } if (hasExpired(view, loanSle->at(sfNextPaymentDueDate))) + { // If the payment is late, and the late payment flag is not set, it'll // fail return normalCost; + } auto const brokerSle = view.read(keylet::loanbroker(loanSle->at(sfLoanBrokerID))); if (!brokerSle) + { // Let preclaim worry about the error for this return normalCost; + } auto const vaultSle = view.read(keylet::vault(brokerSle->at(sfVaultID))); if (!vaultSle) + { // Let preclaim worry about the error for this return normalCost; + } auto const asset = vaultSle->at(sfAsset); if (asset != amount.asset()) + { // Let preclaim worry about the error for this return normalCost; + } auto const scale = loanSle->at(sfLoanScale); @@ -517,9 +529,11 @@ LoanPay::doApply() if (auto const ter = addEmptyHolding( view, brokerPayee, brokerPayeeSle->at(sfBalance).value().xrp(), asset, j_); ter && ter != tecDUPLICATE) + { // ignore tecDUPLICATE. That means the holding already exists, // and is fine here return ter; + } } if (auto const ter = requireAuth(view, asset, brokerPayee, AuthType::StrongAuth)) return ter; diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index 848af47957..7212f079ce 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -62,9 +62,10 @@ LoanSet::preflight(PreflightContext const& ctx) return temINVALID; } // Principal Requested is required - if (auto const p = tx[sfPrincipalRequested]; p <= 0) + auto const p = tx[sfPrincipalRequested]; + if (p <= 0) return temINVALID; - else if (!validNumericRange(tx[~sfLoanOriginationFee], p)) + if (!validNumericRange(tx[~sfLoanOriginationFee], p)) return temINVALID; if (!validNumericRange(tx[~sfInterestRate], maxInterestRate)) return temINVALID; @@ -80,17 +81,16 @@ LoanSet::preflight(PreflightContext const& ctx) if (auto const paymentTotal = tx[~sfPaymentTotal]; paymentTotal && *paymentTotal <= 0) return temINVALID; - if (auto const paymentInterval = tx[~sfPaymentInterval]; - !validNumericMinimum(paymentInterval, LoanSet::minPaymentInterval)) - return temINVALID; - // Grace period is between min default value and payment interval - else if ( - auto const gracePeriod = tx[~sfGracePeriod]; // - !validNumericRange( + auto const paymentInterval = tx[~sfPaymentInterval]; + if (!validNumericMinimum(paymentInterval, LoanSet::minPaymentInterval)) + return temINVALID; // Grace period is between min default value and payment interval + if (auto const gracePeriod = tx[~sfGracePeriod]; !validNumericRange( gracePeriod, paymentInterval.value_or(LoanSet::defaultPaymentInterval), defaultGracePeriod)) + { return temINVALID; + } // Copied from preflight2 if (counterPartySig) @@ -150,12 +150,12 @@ LoanSet::calculateBaseFee(ReadView const& view, STTx const& tx) // for the transaction. Note that unlike the base class, the single signer // is counted if present. It will only be absent in a batch inner // transaction. - std::size_t const signerCount = [&counterSig]() { - // Compute defensively. Assure that "tx" cannot be accessed and cause - // confusion or miscalculations. - return counterSig.isFieldPresent(sfSigners) - ? counterSig.getFieldArray(sfSigners).size() - : (counterSig.isFieldPresent(sfTxnSignature) ? 1 : 0); + std::size_t const signerCount = [&counterSig]() -> int { + // Compute defensively. + // Assure that "tx" cannot be accessed and cause confusion or miscalculations. + if (counterSig.isFieldPresent(sfSigners)) + return counterSig.getFieldArray(sfSigners).size(); + return counterSig.isFieldPresent(sfTxnSignature) ? 1 : 0; }(); return normalCost + (signerCount * baseFee); @@ -266,8 +266,10 @@ LoanSet::preclaim(PreclaimContext const& ctx) auto const vault = ctx.view.read(keylet::vault(brokerSle->at(sfVaultID))); if (!vault) + { // Should be impossible return tefBAD_LEDGER; // LCOV_EXCL_LINE + } if (vault->at(sfAssetsMaximum) != 0 && vault->at(sfAssetsTotal) >= vault->at(sfAssetsMaximum)) { @@ -492,9 +494,11 @@ LoanSet::doApply() if (auto const ter = addEmptyHolding( view, borrower, borrowerSle->at(sfBalance).value().xrp(), vaultAsset, j_); ter && ter != tecDUPLICATE) + { // ignore tecDUPLICATE. That means the holding already exists, and // is fine here return ter; + } if (auto const ter = requireAuth(view, vaultAsset, borrower, AuthType::StrongAuth)) return ter; @@ -513,9 +517,11 @@ LoanSet::doApply() if (auto const ter = addEmptyHolding( view, brokerOwner, brokerOwnerSle->at(sfBalance).value().xrp(), vaultAsset, j_); ter && ter != tecDUPLICATE) + { // ignore tecDUPLICATE. That means the holding already exists, // and is fine here return ter; + } } if (auto const ter = requireAuth(view, vaultAsset, brokerOwner, AuthType::StrongAuth)) diff --git a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp index 15ea1eb074..3022188ccf 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp @@ -271,8 +271,10 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // this nftoken auto const& offer = bo ? bo : so; if (!offer) + { // Purely defensive, should be caught in preflight. return tecINTERNAL; // LCOV_EXCL_LINE + } auto const& tokenID = offer->at(sfNFTokenID); auto const& amount = offer->at(sfAmount); diff --git a/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp b/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp index 538d28718f..7bebbd0070 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp @@ -47,11 +47,16 @@ NFTokenMint::getFlagsMask(PreflightContext const& ctx) // The fixRemoveNFTokenAutoTrustLine amendment disables minting with the // tfTrustLine flag as a way to prevent the attack. But until the // amendment passes we still need to keep the old behavior available. - std::uint32_t const nfTokenMintMask = ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine) - // if featureDynamicNFT enabled then new flag allowing mutable URI available - ? ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMask : tfNFTokenMintMaskWithoutMutable - : ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintOldMaskWithMutable - : tfNFTokenMintOldMask; + std::uint32_t const nfTokenMintMask = [&]() -> std::uint32_t { + if (ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine)) + { + // if featureDynamicNFT enabled then new flag allowing mutable URI available + return ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMask + : tfNFTokenMintMaskWithoutMutable; + } + return ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintOldMaskWithMutable + : tfNFTokenMintOldMask; + }(); return nfTokenMintMask; } @@ -76,7 +81,7 @@ NFTokenMint::preflight(PreflightContext const& ctx) if (auto uri = ctx.tx[~sfURI]) { - if (uri->length() == 0 || uri->length() > maxTokenURILength) + if (uri->empty() || uri->length() > maxTokenURILength) return temMALFORMED; } @@ -202,8 +207,10 @@ NFTokenMint::doApply() auto const tokenSeq = [this, &issuer]() -> Expected { auto const root = view().peek(keylet::account(issuer)); if (root == nullptr) + { // Should not happen. Checked in preclaim. return Unexpected(tecNO_ISSUER); + } // If the issuer hasn't minted an NFToken before we must add a // FirstNFTokenSequence field to the issuer's AccountRoot. The @@ -259,8 +266,10 @@ NFTokenMint::doApply() InnerObjectFormats::getInstance().findSOTemplateBySField(sfNFToken); if (nfTokenTemplate == nullptr) + { // Should never happen. return tecINTERNAL; // LCOV_EXCL_LINE + } auto const nftokenID = createNFTokenID( extractNFTokenFlagsFromTxFlags(ctx_.tx.getFlags()), diff --git a/src/libxrpl/tx/transactors/nft/NFTokenModify.cpp b/src/libxrpl/tx/transactors/nft/NFTokenModify.cpp index af852530e4..1b2c9c2ab0 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenModify.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenModify.cpp @@ -13,7 +13,7 @@ NFTokenModify::preflight(PreflightContext const& ctx) if (auto uri = ctx.tx[~sfURI]) { - if (uri->length() == 0 || uri->length() > maxTokenURILength) + if (uri->empty() || uri->length() > maxTokenURILength) return temMALFORMED; } diff --git a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp index 177092787c..40b7171015 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp @@ -101,9 +101,11 @@ getPageForToken( // equivalent NFTokens then check the front of the page for a // place to make the split. if (splitIter == narr.end()) + { splitIter = std::find_if(narr.begin(), narr.end(), [&cmp](STObject const& obj) { return (obj.getFieldH256(sfNFTokenID) & nft::pageMask) == cmp; }); + } // There should be no circumstance when splitIter == end(), but if it // were to happen we should bail out because something is confused. @@ -218,9 +220,13 @@ changeTokenURI( return tecINTERNAL; // LCOV_EXCL_LINE if (uri) + { nftIter->setFieldVL(sfURI, *uri); + } else if (nftIter->isFieldPresent(sfURI)) + { nftIter->makeFieldAbsent(sfURI); + } view.update(page); return tesSUCCESS; @@ -368,9 +374,11 @@ removeToken( page2 = view.peek(Keylet(ltNFTOKEN_PAGE, *id)); if (!page2) + { Throw( "page " + to_string(page1->key()) + " has a broken " + field.getName() + " field pointing to " + to_string(*id)); + } } return page2; @@ -396,11 +404,13 @@ removeToken( cnt--; if (cnt != 0) + { adjustOwnerCount( view, view.peek(keylet::account(owner)), cnt, beast::Journal{beast::Journal::getNullSink()}); + } return tesSUCCESS; } @@ -448,9 +458,13 @@ removeToken( // The page is empty and not the last page, so we can just unlink it // and then remove it. if (next) + { prev->setFieldH256(sfNextPageMin, next->key()); + } else + { prev->makeFieldAbsent(sfNextPageMin); + } view.update(prev); } @@ -459,9 +473,13 @@ removeToken( { // Make our next page point to our previous page: if (prev) + { next->setFieldH256(sfPreviousPageMin, prev->key()); + } else + { next->makeFieldAbsent(sfPreviousPageMin); + } view.update(next); } @@ -526,8 +544,10 @@ findTokenAndPage(ApplyView& view, AccountID const& owner, uint256 const& nftoken for (auto const& t : page->getFieldArray(sfNFTokens)) { if (t[sfNFTokenID] == nftokenID) + { // This std::optional constructor is explicit, so it is spelled out. return std::optional(std::in_place, t, std::move(page)); + } } return std::nullopt; } @@ -564,10 +584,14 @@ removeTokenOffersWithLimit(ApplyView& view, Keylet const& directory, std::size_t if (auto const offer = view.peek(keylet::nftoffer(offerIndexes[i]))) { if (deleteTokenOffer(view, offer)) + { ++deletedOffersCount; + } else + { Throw( "Offer " + to_string(offerIndexes[i]) + " cannot be deleted!"); + } } if (maxDeletableOffers == deletedOffersCount) @@ -696,8 +720,10 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner) } if (nextPage->key() == last.key) + { // We need special handling for the last page. break; + } page = nextPage; } @@ -727,9 +753,11 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner) // Also fix up the NextPageMin link in the new Previous. auto const newPrev = view.peek(Keylet(ltNFTOKEN_PAGE, *prevLink)); if (!newPrev) + { Throw( "NFTokenPage directory for " + to_string(owner) + " cannot be repaired. Unexpected link problem."); + } newPrev->at(sfNextPageMin) = nextPage->key(); view.update(newPrev); } @@ -760,8 +788,10 @@ tokenOfferCreatePreflight( std::uint32_t txFlags) { if (amount.negative()) + { // An offer for a negative amount makes no sense. return temBAD_AMOUNT; + } if (!isXRP(amount)) { diff --git a/src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp b/src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp index 5452096b6d..78bba900da 100644 --- a/src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp +++ b/src/libxrpl/tx/transactors/oracle/DeleteOracle.cpp @@ -18,14 +18,15 @@ DeleteOracle::preclaim(PreclaimContext const& ctx) if (!ctx.view.exists(keylet::account(ctx.tx.getAccountID(sfAccount)))) return terNO_ACCOUNT; // LCOV_EXCL_LINE - if (auto const sle = ctx.view.read( - keylet::oracle(ctx.tx.getAccountID(sfAccount), ctx.tx[sfOracleDocumentID])); - !sle) + auto const sle = + ctx.view.read(keylet::oracle(ctx.tx.getAccountID(sfAccount), ctx.tx[sfOracleDocumentID])); + if (!sle) { JLOG(ctx.j.debug()) << "Oracle Delete: Oracle does not exist."; return tecNO_ENTRY; } - else if (ctx.tx.getAccountID(sfAccount) != sle->getAccountID(sfOwner)) + + if (ctx.tx.getAccountID(sfAccount) != sle->getAccountID(sfOwner)) { // this can't happen because of the above check // LCOV_EXCL_START diff --git a/src/libxrpl/tx/transactors/oracle/SetOracle.cpp b/src/libxrpl/tx/transactors/oracle/SetOracle.cpp index be827c25d5..62ca6c5ea0 100644 --- a/src/libxrpl/tx/transactors/oracle/SetOracle.cpp +++ b/src/libxrpl/tx/transactors/oracle/SetOracle.cpp @@ -77,11 +77,17 @@ SetOracle::preclaim(PreclaimContext const& ctx) if (entry[~sfScale] > maxPriceScale) return temMALFORMED; if (entry.isFieldPresent(sfAssetPrice)) + { pairs.emplace(key); + } else if (sle) + { pairsDel.emplace(key); + } else + { return temMALFORMED; + } } // Lambda is used to check if the value of a field, passed @@ -111,9 +117,13 @@ SetOracle::preclaim(PreclaimContext const& ctx) if (!pairs.contains(key)) { if (pairsDel.contains(key)) + { pairsDel.erase(key); + } else + { pairs.emplace(key); + } } } if (!pairsDel.empty()) diff --git a/src/libxrpl/tx/transactors/payment/Payment.cpp b/src/libxrpl/tx/transactors/payment/Payment.cpp index 8663a70b9e..8bf86b7b38 100644 --- a/src/libxrpl/tx/transactors/payment/Payment.cpp +++ b/src/libxrpl/tx/transactors/payment/Payment.cpp @@ -33,15 +33,19 @@ getMaxSourceAmount( std::optional const& sendMax) { if (sendMax) + { return *sendMax; - else if (dstAmount.native() || dstAmount.holds()) + } + if (dstAmount.native() || dstAmount.holds()) + { return dstAmount; - else - return STAmount( - Issue{dstAmount.get().currency, account}, - dstAmount.mantissa(), - dstAmount.exponent(), - dstAmount < beast::zero); + } + + return STAmount( + Issue{dstAmount.get().currency, account}, + dstAmount.mantissa(), + dstAmount.exponent(), + dstAmount < beast::zero); } bool @@ -282,7 +286,7 @@ Payment::preclaim(PreclaimContext const& ctx) // transaction would succeed. return tecNO_DST; } - else if (ctx.view.open() && partialPaymentAllowed) + if (ctx.view.open() && partialPaymentAllowed) { // You cannot fund an account with a partial payment. // Make retry work smaller, by rejecting this. @@ -293,7 +297,7 @@ Payment::preclaim(PreclaimContext const& ctx) // transaction would succeed. return telNO_DST_PARTIAL; } - else if (dstAmount < STAmount(ctx.view.fees().reserve)) + if (dstAmount < STAmount(ctx.view.fees().reserve)) { // accountReserve is the minimum amount that an account can have. // Reserve is not scaled by load. @@ -438,9 +442,13 @@ Payment::doApply() if (isTesSuccess(rc.result()) && rc.actualAmountOut != dstAmount) { if (deliverMin && rc.actualAmountOut < *deliverMin) + { rc.setResult(tecPATH_PARTIAL); + } else + { ctx_.deliver(rc.actualAmountOut); + } } auto terResult = rc.result(); @@ -453,7 +461,7 @@ Payment::doApply() terResult = tecPATH_DRY; return terResult; } - else if (mptDirect) + if (mptDirect) { JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText(); auto const& mptIssue = dstAmount.get(); @@ -524,7 +532,9 @@ Payment::doApply() ctx_.deliver(amountDeliver); } else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY) + { res = tecPATH_PARTIAL; + } return res; } diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp b/src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp index d41e6f043c..e70c1f11ac 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PayChanClaim.cpp @@ -135,8 +135,10 @@ PayChanClaim::doApply() return tecUNFUNDED_PAYMENT; if (reqBalance <= chanBalance) + { // nothing requested return tecUNFUNDED_PAYMENT; + } auto const sled = ctx_.view().peek(keylet::account(dst)); if (!sled) diff --git a/src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp b/src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp index eb6fe1d2a9..f01b8a7c40 100644 --- a/src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp +++ b/src/libxrpl/tx/transactors/payment_channel/PayChanFund.cpp @@ -42,8 +42,10 @@ PayChanFund::doApply() } if (src != txAccount) + { // only the owner can add funds or extend return tecNO_PERMISSION; + } if (auto extend = ctx_.tx[~sfExpiration]) { diff --git a/src/libxrpl/tx/transactors/system/Batch.cpp b/src/libxrpl/tx/transactors/system/Batch.cpp index d27c42f88f..b2a111a182 100644 --- a/src/libxrpl/tx/transactors/system/Batch.cpp +++ b/src/libxrpl/tx/transactors/system/Batch.cpp @@ -105,9 +105,13 @@ Batch::calculateBaseFee(ReadView const& view, STTx const& tx) for (STObject const& signer : signers) { if (signer.isFieldPresent(sfTxnSignature)) + { signerCount += 1; + } else if (signer.isFieldPresent(sfSigners)) + { signerCount += signer.getFieldArray(sfSigners).size(); + } } } diff --git a/src/libxrpl/tx/transactors/system/Change.cpp b/src/libxrpl/tx/transactors/system/Change.cpp index d1e2d148d6..5b0a431004 100644 --- a/src/libxrpl/tx/transactors/system/Change.cpp +++ b/src/libxrpl/tx/transactors/system/Change.cpp @@ -222,9 +222,13 @@ Change::applyAmendment() } if (newMajorities.empty()) + { amendmentObject->makeFieldAbsent(sfMajorities); + } else + { amendmentObject->setFieldArray(sfMajorities, newMajorities); + } view().update(amendmentObject); diff --git a/src/libxrpl/tx/transactors/token/Clawback.cpp b/src/libxrpl/tx/transactors/token/Clawback.cpp index c64459faa9..a3ac810e90 100644 --- a/src/libxrpl/tx/transactors/token/Clawback.cpp +++ b/src/libxrpl/tx/transactors/token/Clawback.cpp @@ -168,9 +168,13 @@ Clawback::preclaim(PreclaimContext const& ctx) // Note the order of checks - when SAV is active, this check here will make // the one which follows `sleHolder->isFieldPresent(sfAMMID)` redundant. if (ctx.view.rules().enabled(featureSingleAssetVault) && isPseudoAccount(sleHolder)) + { return tecPSEUDO_ACCOUNT; - else if (sleHolder->isFieldPresent(sfAMMID)) + } + if (sleHolder->isFieldPresent(sfAMMID)) + { return tecAMM_ACCOUNT; + } return std::visit( [&](T const&) { diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp index f9b9f9c01e..9f9362da4e 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp @@ -58,7 +58,7 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx) if (auto const metadata = ctx.tx[~sfMPTokenMetadata]) { - if (metadata->length() == 0 || metadata->length() > maxMPTokenMetadataLength) + if (metadata->empty() || metadata->length() > maxMPTokenMetadataLength) return temMALFORMED; } diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp index 5676ebd6af..dc5827419b 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp @@ -158,9 +158,13 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) // For readability two separate `if` rather than `||` of two conditions if (!ctx.view.rules().enabled(featureSingleAssetVault) && !ctx.view.rules().enabled(featureDynamicMPT)) + { return tecNO_PERMISSION; - else if (ctx.tx.isFlag(tfMPTLock) || ctx.tx.isFlag(tfMPTUnlock)) + } + if (ctx.tx.isFlag(tfMPTLock) || ctx.tx.isFlag(tfMPTUnlock)) + { return tecNO_PERMISSION; + } } // ensure it is issued by the tx submitter @@ -240,9 +244,13 @@ MPTokenIssuanceSet::doApply() std::shared_ptr sle; if (holderID) + { sle = view().peek(keylet::mptoken(mptIssuanceID, *holderID)); + } else + { sle = view().peek(keylet::mptIssuance(mptIssuanceID)); + } if (!sle) return tecINTERNAL; // LCOV_EXCL_LINE @@ -251,18 +259,26 @@ MPTokenIssuanceSet::doApply() std::uint32_t flagsOut = flagsIn; if (txFlags & tfMPTLock) + { flagsOut |= lsfMPTLocked; + } else if (txFlags & tfMPTUnlock) + { flagsOut &= ~lsfMPTLocked; + } if (auto const mutableFlags = ctx_.tx[~sfMutableFlags].value_or(0)) { for (auto const& f : mptMutabilityFlags) { if (mutableFlags & f.setFlag) + { flagsOut |= f.canMutateFlag; + } else if (mutableFlags & f.clearFlag) + { flagsOut &= ~f.canMutateFlag; + } } if (mutableFlags & tmfMPTClearCanTransfer) @@ -283,17 +299,25 @@ MPTokenIssuanceSet::doApply() // - If the field is present, it must be non-zero. // Therefore, when TransferFee is 0, the field should be removed. if (transferFee == 0) + { sle->makeFieldAbsent(sfTransferFee); + } else + { sle->setFieldU16(sfTransferFee, *transferFee); + } } if (auto const metadata = ctx_.tx[~sfMPTokenMetadata]) { if (metadata->empty()) + { sle->makeFieldAbsent(sfMPTokenMetadata); + } else + { sle->setFieldVL(sfMPTokenMetadata, *metadata); + } } if (domainID) diff --git a/src/libxrpl/tx/transactors/token/SetTrust.cpp b/src/libxrpl/tx/transactors/token/SetTrust.cpp index 76e586d2d3..7140d5ef2a 100644 --- a/src/libxrpl/tx/transactors/token/SetTrust.cpp +++ b/src/libxrpl/tx/transactors/token/SetTrust.cpp @@ -214,7 +214,9 @@ SetTrust::preclaim(PreclaimContext const& ctx) // pass } else + { return tecNO_PERMISSION; + } } // In general, trust lines to pseudo accounts are not permitted, unless @@ -233,14 +235,20 @@ SetTrust::preclaim(PreclaimContext const& ctx) } else if (auto const ammSle = ctx.view.read({ltAMM, sleDst->getFieldH256(sfAMMID)})) { - if (auto const lpTokens = ammSle->getFieldAmount(sfLPTokenBalance); - lpTokens == beast::zero) + auto const lpTokens = ammSle->getFieldAmount(sfLPTokenBalance); + if (lpTokens == beast::zero) + { return tecAMM_EMPTY; - else if (lpTokens.getCurrency() != saLimitAmount.getCurrency()) + } + if (lpTokens.getCurrency() != saLimitAmount.getCurrency()) + { return tecNO_PERMISSION; + } } else + { return tecINTERNAL; // LCOV_EXCL_LINE + } } else if (sleDst->isFieldPresent(sfVaultID) || sleDst->isFieldPresent(sfLoanBrokerID)) { @@ -249,7 +257,9 @@ SetTrust::preclaim(PreclaimContext const& ctx) // else pass } else + { return tecPSEUDO_ACCOUNT; + } } // Checking all freeze/deep freeze flag invariants. @@ -473,11 +483,14 @@ SetTrust::doApply() if (bSetNoRipple && !bClearNoRipple) { if ((bHigh ? saHighBalance : saLowBalance) >= beast::zero) + { uFlagsOut |= (bHigh ? lsfHighNoRipple : lsfLowNoRipple); - + } else + { // Cannot set noRipple on a negative balance. return tecNO_PERMISSION; + } } else if (bClearNoRipple && !bSetNoRipple) { diff --git a/src/libxrpl/tx/transactors/vault/VaultClawback.cpp b/src/libxrpl/tx/transactors/vault/VaultClawback.cpp index bfce93b1dd..ed47dfb63d 100644 --- a/src/libxrpl/tx/transactors/vault/VaultClawback.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultClawback.cpp @@ -27,8 +27,10 @@ VaultClawback::preflight(PreflightContext const& ctx) { // Note, zero amount is valid, it means "all". It is also the default. if (*amount < beast::zero) + { return temBAD_AMOUNT; - else if (isXRP(amount->asset())) + } + if (isXRP(amount->asset())) { JLOG(ctx.j.debug()) << "VaultClawback: cannot clawback XRP."; return temMALFORMED; diff --git a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp index 4e9faeb56c..a5b039f06b 100644 --- a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp @@ -50,9 +50,13 @@ VaultCreate::preflight(PreflightContext const& ctx) if (auto const domain = ctx.tx[~sfDomainID]) { if (*domain == beast::zero) + { return temMALFORMED; - else if ((ctx.tx.getFlags() & tfVaultPrivate) == 0) + } + if ((ctx.tx.getFlags() & tfVaultPrivate) == 0) + { return temMALFORMED; // DomainID only allowed on private vaults + } } if (auto const assetMax = ctx.tx[~sfAssetsMaximum]) @@ -63,7 +67,7 @@ VaultCreate::preflight(PreflightContext const& ctx) if (auto const metadata = ctx.tx[~sfMPTokenMetadata]) { - if (metadata->length() == 0 || metadata->length() > maxMPTokenMetadataLength) + if (metadata->empty() || metadata->length() > maxMPTokenMetadataLength) return temMALFORMED; } @@ -197,9 +201,13 @@ VaultCreate::doApply() vault->at(sfData) = *value; // Required field, default to vaultStrategyFirstComeFirstServe if (auto value = tx[~sfWithdrawalPolicy]) + { vault->at(sfWithdrawalPolicy) = *value; + } else + { vault->at(sfWithdrawalPolicy) = vaultStrategyFirstComeFirstServe; + } if (scale) vault->at(sfScale) = scale; view().insert(vault); diff --git a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp index fe3d8d313a..66f4fb09b8 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp @@ -101,7 +101,9 @@ VaultDeposit::preclaim(PreclaimContext const& ctx) return err; } else + { return tecNO_AUTH; + } } // Source MPToken must exist (if asset is an MPT) @@ -196,8 +198,10 @@ VaultDeposit::doApply() auto const maybeAssets = sharesToAssetsDeposit(vault, sleIssuance, sharesCreated); if (!maybeAssets) + { return tecINTERNAL; // LCOV_EXCL_LINE - else if (*maybeAssets > amount) + } + if (*maybeAssets > amount) { // LCOV_EXCL_START JLOG(j_.error()) << "VaultDeposit: would take more than offered."; diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index 725c54a3fd..a473ac7c36 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -144,7 +144,9 @@ VaultWithdraw::doApply() assetsWithdrawn = *maybeAssets; } else + { return tefINTERNAL; // LCOV_EXCL_LINE + } } catch (std::overflow_error const&) { diff --git a/src/test/app/AMMCalc_test.cpp b/src/test/app/AMMCalc_test.cpp index 690329d2f3..c1068b08ba 100644 --- a/src/test/app/AMMCalc_test.cpp +++ b/src/test/app/AMMCalc_test.cpp @@ -43,10 +43,14 @@ class AMMCalc_test : public beast::unit_test::suite if (delimited) *delimited = (match[3] != ""); if (match[1] == "XRP") + { return XRP(std::stoll(match[2])); - // drops - else if (match[1] == "XRPA") + // drops + } + if (match[1] == "XRPA") + { return XRPAmount{std::stoll(match[2])}; + } return amountFromString(gw[match[1]].asset(), match[2]); } return std::nullopt; @@ -120,7 +124,9 @@ class AMMCalc_test : public beast::unit_test::suite break; } else + { return std::nullopt; + } } return rates; } @@ -398,13 +404,17 @@ class AMMCalc_test : public beast::unit_test::suite env.current()->rules(), beast::Journal(beast::Journal::getNullSink())); ammOffer) + { std::cout << "amm offer: " << toString(ammOffer->in) << " " << toString(ammOffer->out) << "\nnew pool: " << toString(pool->first.in + ammOffer->in) << " " << toString(pool->first.out - ammOffer->out) << std::endl; + } else + { std::cout << "can't change the pool's SP quality" << std::endl; + } return true; } } diff --git a/src/test/app/AMMClawback_test.cpp b/src/test/app/AMMClawback_test.cpp index 3034c628f4..9033fe2bdd 100644 --- a/src/test/app/AMMClawback_test.cpp +++ b/src/test/app/AMMClawback_test.cpp @@ -531,11 +531,15 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999579, -12})); + } // gw clawback 1000 USD from the AMM pool env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), ter(tesSUCCESS)); @@ -554,17 +558,25 @@ class AMMClawback_test : public beast::unit_test::suite // 1000 USD and 1250 EUR was withdrawn from the AMM pool, so the // current balance is 3000 USD and 3750 EUR. if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(3000), EUR(3750), IOUAmount{3354101966249685, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(3000), EUR(3750), IOUAmount{3354101966249684, -12})); + } // Alice has 3/4 of its initial lptokens Left. if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{3354101966249685, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{3354101966249684, -12})); + } // gw clawback another 500 USD from the AMM pool. env(amm::ammClawback(gw, alice, USD, EUR, USD(500)), ter(tesSUCCESS)); @@ -575,19 +587,27 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(alice, USD(2000))); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2500000000000001), -12}, STAmount{EUR, UINT64_C(3125000000000001), -12}, IOUAmount{2795084971874738, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(2500), EUR(3125), IOUAmount{2795084971874737, -12})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(alice, EUR) == STAmount(EUR, UINT64_C(2874999999999999), -12)); + } else + { BEAST_EXPECT(env.balance(alice, EUR) == EUR(2875)); + } // gw clawback small amount, 1 USD. env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), ter(tesSUCCESS)); @@ -597,27 +617,39 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(alice, USD(2000))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2499000000000002), -12}, STAmount{EUR, UINT64_C(3123750000000002), -12}, IOUAmount{2793966937885989, -12})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(2499), EUR(3123.75), IOUAmount{2793966937885987, -12})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2499000000000001), -12}, STAmount{EUR, UINT64_C(3123750000000001), -12}, IOUAmount{2793966937885988, -12})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT( env.balance(alice, EUR) == STAmount(EUR, UINT64_C(2876'249999999998), -12)); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(env.balance(alice, EUR) == EUR(2876.25)); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(alice, EUR) == STAmount(EUR, UINT64_C(2876'249999999999), -12)); + } // gw clawback 4000 USD, exceeding the current balance. We // will clawback all. @@ -685,27 +717,39 @@ class AMMClawback_test : public beast::unit_test::suite // gw2 creates AMM pool of XRP/EUR, alice and bob deposit XRP/EUR. AMM amm2(env, gw2, XRP(3000), EUR(1000), ter(tesSUCCESS)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); + } else + { BEAST_EXPECT( amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); + } amm2.deposit(alice, EUR(1000), XRP(3000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); + } else + { BEAST_EXPECT( amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); + } amm2.deposit(bob, EUR(1000), XRP(3000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm2.expectBalances(EUR(3000), XRP(9000), IOUAmount{5196152422706634, -9})); + } else + { BEAST_EXPECT( amm2.expectBalances(EUR(3000), XRP(9000), IOUAmount{5196152422706631, -9})); + } env.close(); auto aliceXrpBalance = env.balance(alice, XRP); @@ -725,28 +769,44 @@ class AMMClawback_test : public beast::unit_test::suite // Alice gets 1000 XRP back. if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT( expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000) - XRPAmount(1))); + } else + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + } aliceXrpBalance = env.balance(alice, XRP); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(2500), XRP(5000), IOUAmount{3535533905932738, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(2500), XRP(5000), IOUAmount{3535533905932737, -9})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( USD(2500), XRPAmount(5000000001), IOUAmount{3'535'533'905932738, -9})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865480, -10})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865474, -10})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); + } BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1414213562373095, -9})); @@ -762,32 +822,50 @@ class AMMClawback_test : public beast::unit_test::suite bobXrpBalance = env.balance(bob, XRP); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2490000000000001), -12}, XRP(4980), IOUAmount{3521391770309008, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(2'490), XRP(4980), IOUAmount{3521391770309006, -9})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(2490000000000001), -12}, XRPAmount(4980000001), IOUAmount{3521391'770309008, -9})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865480, -10})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{7071067811865474, -10})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{707106781186548, -9})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + } // gw2 clawback 200 EUR from amm2. env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(200)), ter(tesSUCCESS)); @@ -797,32 +875,52 @@ class AMMClawback_test : public beast::unit_test::suite env.require(balance(bob, EUR(3000))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(600))); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(600))); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT( expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(600) - XRPAmount{1})); + } aliceXrpBalance = env.balance(alice, XRP); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm2.expectBalances(EUR(2800), XRP(8400), IOUAmount{4849742261192859, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm2.expectBalances(EUR(2800), XRP(8400), IOUAmount{4849742261192856, -9})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm2.expectBalances( EUR(2800), XRPAmount(8400000001), IOUAmount{4849742261192856, -9})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount{1385640646055103, -9})); + } else + { BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount{1385640646055102, -9})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount{1732050807568878, -9})); + } else + { BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount{1732050807568877, -9})); + } // gw claw back 1000 USD from alice in amm, which exceeds alice's // balance. This will clawback all the remaining LP tokens of alice @@ -835,35 +933,53 @@ class AMMClawback_test : public beast::unit_test::suite // Alice gets 1000 XRP back. if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000) - XRPAmount{1})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + } aliceXrpBalance = env.balance(alice, XRP); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9})); + } else if (features[fixAMMClawbackRounding] && features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(1990000000000001), -12}, XRP(3980), IOUAmount{2814284989122460, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( USD(1'990), XRPAmount{3'980'000'001}, IOUAmount{2814284989122459, -9})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(1990000000000001), -12}, XRPAmount{3'980'000'001}, IOUAmount{2814284989122460, -9})); + } // gw clawback 1000 USD from bob in amm, which also exceeds bob's // balance in amm. All bob's lptoken in amm will be consumed, which @@ -903,14 +1019,20 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm2.expectBalances(EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm2.expectBalances( EUR(2000), XRPAmount(6000000001), IOUAmount{3464101615137754, -9})); + } // gw2 claw back 2000 EUR from bob in amm2, which exceeds bob's // balance. All bob's lptokens will be consumed, which corresponds @@ -933,14 +1055,20 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount(0))); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm2.expectBalances(EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm2.expectBalances( EUR(1000), XRPAmount(3000000001), IOUAmount{1732050807568877, -9})); + } } } @@ -999,38 +1127,62 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(4000), EUR(5000), IOUAmount{4472135954999579, -12})); + } amm.deposit(bob, USD(2000), EUR(2500)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(6000), EUR(7500), IOUAmount{6708203932499370, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(6000), EUR(7500), IOUAmount{6708203932499368, -12})); + } amm.deposit(carol, USD(1000), EUR(1250)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(7000), EUR(8750), IOUAmount{7826237921249265, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(7000), EUR(8750), IOUAmount{7826237921249262, -12})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{2236067977499790, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{2236067977499789, -12})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749895, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749894, -12})); + } env.require(balance(alice, USD(2000))); env.require(balance(alice, EUR(1000))); @@ -1044,25 +1196,37 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(4999999999999999), -12}, STAmount{EUR, UINT64_C(6249999999999999), -12}, IOUAmount{5590169943749475, -12})); + } else + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(5000000000000001), -12}, STAmount{EUR, UINT64_C(6250000000000001), -12}, IOUAmount{5590169943749473, -12})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12})); + } BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749895, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount{1118033988749894, -12})); + } // Bob will get 2500 EUR back. env.require(balance(alice, USD(2000))); @@ -1070,11 +1234,15 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob, USD) == STAmount(USD, UINT64_C(3000000000000000), -12)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(bob, EUR) == STAmount(EUR, UINT64_C(5000000000000001), -12)); + } else + { BEAST_EXPECT( env.balance(bob, EUR) == STAmount(EUR, UINT64_C(4999999999999999), -12)); + } env.require(balance(carol, USD(3000))); env.require(balance(carol, EUR(2750))); @@ -1082,20 +1250,28 @@ class AMMClawback_test : public beast::unit_test::suite env(amm::ammClawback(gw2, carol, EUR, USD, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(3999999999999999), -12}, STAmount{EUR, UINT64_C(4999999999999999), -12}, IOUAmount{4472135954999580, -12})); + } else + { BEAST_EXPECT(amm.expectBalances( STAmount{USD, UINT64_C(4000000000000001), -12}, STAmount{EUR, UINT64_C(5000000000000002), -12}, IOUAmount{4472135954999579, -12})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12})); + } BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(0))); @@ -1134,25 +1310,37 @@ class AMMClawback_test : public beast::unit_test::suite // gw creates AMM pool of XRP/USD, alice and bob deposit XRP/USD. AMM amm(env, gw, XRP(2000), USD(10000), ter(tesSUCCESS)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(10000), XRP(2000), IOUAmount{4472135954999579, -9})); + } amm.deposit(alice, USD(1000), XRP(200)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(11000), XRP(2200), IOUAmount{4919349550499538, -9})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(11000), XRP(2200), IOUAmount{4919349550499536, -9})); + } amm.deposit(bob, USD(2000), XRP(400)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(13000), XRP(2600), IOUAmount{5813776741499453, -9})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(13000), XRP(2600), IOUAmount{5813776741499451, -9})); + } env.close(); auto aliceXrpBalance = env.balance(alice, XRP); @@ -1162,27 +1350,39 @@ class AMMClawback_test : public beast::unit_test::suite env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(12000), XRP(2400), IOUAmount{5366563145999495, -9})); + } else + { BEAST_EXPECT(amm.expectBalances( USD(12000), XRPAmount(2400000001), IOUAmount{5366563145999494, -9})); + } if (!features[fixAMMv1_3]) + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(200))); + } else + { BEAST_EXPECT( expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(200) - XRPAmount{1})); + } BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); // gw clawback all bob's USD in amm. (2000 USD / 400 XRP) env(amm::ammClawback(gw, bob, USD, XRP, std::nullopt), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT( amm.expectBalances(USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); + } else + { BEAST_EXPECT(amm.expectBalances( USD(10000), XRPAmount(2000000001), IOUAmount{4472135954999579, -9})); + } BEAST_EXPECT(expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(400))); BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); @@ -1237,9 +1437,13 @@ class AMMClawback_test : public beast::unit_test::suite amm.deposit(bob, USD(4000), EUR(1000)); BEAST_EXPECT(amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); if (!features[fixAMMv1_3]) + { amm.deposit(carol, USD(2000), EUR(500)); + } else + { amm.deposit(carol, USD(2000.25), EUR(500)); + } BEAST_EXPECT(amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); // gw clawback 1000 USD from carol. env(amm::ammClawback(gw, carol, USD, EUR, USD(1000)), ter(tesSUCCESS)); @@ -1254,10 +1458,14 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); + } // 250 EUR goes back to carol. BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); @@ -1279,10 +1487,14 @@ class AMMClawback_test : public beast::unit_test::suite // 250 EUR did not go back to bob because tfClawTwoAssets is set. BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); + } BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); // gw clawback all USD from alice and set tfClawTwoAssets. @@ -1300,10 +1512,14 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); + } BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); } @@ -1460,17 +1676,25 @@ class AMMClawback_test : public beast::unit_test::suite env(amm::ammClawback(gw, gw2, USD, EUR, USD(1000)), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(5000), EUR(10000), IOUAmount{7071067811865475, -12})); + } else + { BEAST_EXPECT( amm.expectBalances(USD(5000), EUR(10000), IOUAmount{7071067811865474, -12})); + } BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{1414213562373095, -12})); if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + } BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); @@ -1482,30 +1706,46 @@ class AMMClawback_test : public beast::unit_test::suite env(amm::ammClawback(gw2, gw, EUR, USD, EUR(1000)), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( USD(4500), STAmount(EUR, UINT64_C(9000000000000001), -12), IOUAmount{6363961030678928, -12})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(4500), EUR(9000), IOUAmount{6363961030678928, -12})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( USD(4500), STAmount(EUR, UINT64_C(9000000000000001), -12), IOUAmount{6363961030678927, -12})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + } if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + } BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); @@ -1518,30 +1758,46 @@ class AMMClawback_test : public beast::unit_test::suite env(amm::ammClawback(gw2, alice, EUR, USD, EUR(4000)), ter(tesSUCCESS)); env.close(); if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( USD(2500), STAmount(EUR, UINT64_C(5000000000000001), -12), IOUAmount{3535533905932738, -12})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT( amm.expectBalances(USD(2500), EUR(5000), IOUAmount{3535533905932738, -12})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectBalances( USD(2500), STAmount(EUR, UINT64_C(5000000000000001), -12), IOUAmount{3535533905932737, -12})); + } if (!features[fixAMMv1_3] && !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + } else if (!features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13})); + } else if (features[fixAMMv1_3] && features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + } if (!features[fixAMMv1_3] || !features[fixAMMClawbackRounding]) + { BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + } else + { BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373094, -12})); + } BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount{1414213562373095, -12})); BEAST_EXPECT(env.balance(alice, USD) == USD(4000)); @@ -1791,9 +2047,13 @@ class AMMClawback_test : public beast::unit_test::suite amm.deposit(bob, USD(4000), EUR(1000)); BEAST_EXPECT(amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); if (!features[fixAMMv1_3]) + { amm.deposit(carol, USD(2000), EUR(500)); + } else + { amm.deposit(carol, USD(2000.25), EUR(500)); + } BEAST_EXPECT(amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); // global freeze @@ -1813,10 +2073,14 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); + } // 250 EUR goes back to carol. BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); @@ -1838,10 +2102,14 @@ class AMMClawback_test : public beast::unit_test::suite // 250 EUR did not go back to bob because tfClawTwoAssets is set. BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); + } BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); // gw clawback all USD from alice and set tfClawTwoAssets. @@ -1859,10 +2127,14 @@ class AMMClawback_test : public beast::unit_test::suite BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(5999'999999999999), -12)); + } BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); } } @@ -1911,16 +2183,24 @@ class AMMClawback_test : public beast::unit_test::suite env.close(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(amm.expectBalances( STAmount(USD, UINT64_C(5656854249492380), -13), XRP(70.710678), IOUAmount(200000))); + } else + { BEAST_EXPECT(amm.expectBalances( STAmount(USD, UINT64_C(565'685424949238), -12), XRP(70.710679), IOUAmount(200000))); + } BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(29.289322))); + } else + { BEAST_EXPECT(expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(29.289321))); + } } void diff --git a/src/test/app/AMMExtended_test.cpp b/src/test/app/AMMExtended_test.cpp index 14be260822..93ad92af3d 100644 --- a/src/test/app/AMMExtended_test.cpp +++ b/src/test/app/AMMExtended_test.cpp @@ -1971,8 +1971,10 @@ private: return false; Sandbox sb(&view, tapNONE); for (auto const& o : flowResult.removableOffers) + { if (auto ok = sb.peek(keylet::offer(o))) offerDelete(sb, ok, flowJournal); + } sb.apply(view); return true; }); @@ -2633,9 +2635,13 @@ private: // offer, removes 999 more as unfunded, then hits the step limit. env(offer(alice, USD(1'000), XRP(1'000))); if (!features[fixAMMv1_1]) + { env.require(balance(alice, STAmount{USD, UINT64_C(2'050126257867561), -15})); + } else + { env.require(balance(alice, STAmount{USD, UINT64_C(2'050125257867587), -15})); + } env.require(owners(alice, 2)); env.require(balance(bob, USD(0))); env.require(owners(bob, 1'001)); diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 44ec1f039e..152a97fece 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -739,16 +739,20 @@ private: [&](AMM& ammAlice, Env& env) { env(fset(gw, asfGlobalFreeze)); if (!features[featureAMMClawback]) + { // If the issuer set global freeze, the holder still can // deposit the other non-frozen token when AMMClawback is // not enabled. ammAlice.deposit(carol, XRP(100)); + } else + { // If the issuer set global freeze, the holder cannot // deposit the other non-frozen token when AMMClawback is // enabled. ammAlice.deposit( carol, XRP(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + } ammAlice.deposit( carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); @@ -766,14 +770,18 @@ private: env(trust(gw, carol["USD"](0), tfSetFreeze)); env.close(); if (!features[featureAMMClawback]) + { // Can deposit non-frozen token if AMMClawback is not // enabled ammAlice.deposit(carol, XRP(100)); + } else + { // Cannot deposit non-frozen token if the other token is // frozen when AMMClawback is enabled ammAlice.deposit( carol, XRP(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + } ammAlice.deposit(carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); ammAlice.deposit( @@ -837,14 +845,18 @@ private: env.close(); if (features[featureAMMClawback]) + { // if featureAMMClawback is enabled, bob can not deposit XRP // because he's not authorized to hold the paired token // gw["USD"]. amm.deposit( bob, XRP(10), std::nullopt, std::nullopt, std::nullopt, ter(tecNO_AUTH)); + } else + { amm.deposit( bob, XRP(10), std::nullopt, std::nullopt, std::nullopt, ter(tesSUCCESS)); + } } // Insufficient XRP balance @@ -1687,8 +1699,10 @@ private: ammAlice.withdraw( alice, IOUAmount{9'999'999'9999, -4}, std::nullopt, std::nullopt, err); if (env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(1), STAmount{USD, 1, -7}, IOUAmount{1, -4})); + } }, std::nullopt, 0, @@ -1707,8 +1721,10 @@ private: ammAlice.withdraw( alice, IOUAmount{9'999'999'999999999, -9}, std::nullopt, std::nullopt, err); if (env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(1), STAmount{USD, 1, -11}, IOUAmount{1, -8})); + } }, std::nullopt, 0, @@ -1932,11 +1948,15 @@ private: [&](AMM& ammAlice, Env& env) { ammAlice.withdraw(alice, XRP(1'000)); if (!env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(9'000), USD(10'000), IOUAmount{9'486'832'98050514, -8})); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{9'000'000'001}, USD(10'000), IOUAmount{9'486'832'98050514, -8})); + } }, std::nullopt, 0, @@ -2000,11 +2020,15 @@ private: lpTokens = ammAlice.deposit(carol, XRPAmount(1)); ammAlice.withdraw(carol, lpTokens, XRPAmount(0)); if (!env.enabled(fixAMMv1_3)) + { BEAST_EXPECT( ammAlice.expectBalances(XRP(10'000), USD(10'000), ammAlice.tokens())); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(10'000'000'001), USD(10'000), ammAlice.tokens())); + } BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); }, std::nullopt, @@ -2057,20 +2081,26 @@ private: ammAlice.withdraw(carol, USD(100), std::nullopt, IOUAmount{520, 0}); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{153'846'15384616, -8})); if (!env.enabled(fixAMMv1_1) && !env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(11'000'000'000), STAmount{USD, UINT64_C(9'372'781065088757), -12}, IOUAmount{10'153'846'15384616, -8})); + } else if (env.enabled(fixAMMv1_1) && !env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(11'000'000'000), STAmount{USD, UINT64_C(9'372'781065088769), -12}, IOUAmount{10'153'846'15384616, -8})); + } else if (env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(11'000'000'000), STAmount{USD, UINT64_C(9'372'78106508877), -11}, IOUAmount{10'153'846'15384616, -8})); + } ammAlice.withdrawAll(carol); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); }, @@ -2083,20 +2113,26 @@ private: ammAlice.withdraw(carol, USD(0), std::nullopt, IOUAmount{520, 0}); BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{153'846'15384616, -8})); if (!env.enabled(fixAMMv1_1) && !env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(11'000), STAmount{USD, UINT64_C(9'372'781065088757), -12}, IOUAmount{10'153'846'15384616, -8})); + } else if (env.enabled(fixAMMv1_1) && !env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(11'000), STAmount{USD, UINT64_C(9'372'781065088769), -12}, IOUAmount{10'153'846'15384616, -8})); + } else if (env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(11'000), STAmount{USD, UINT64_C(9'372'78106508877), -11}, IOUAmount{10'153'846'15384616, -8})); + } }, std::nullopt, 0, @@ -2142,11 +2178,15 @@ private: // Single XRP pool ammAlice.withdraw(alice, std::nullopt, XRPAmount{1}); if (!env.enabled(fixAMMv1_3)) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{9'999'999'999}, USD(10'000), IOUAmount{9'999'999'9995, -4})); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRP(10'000), USD(10'000), IOUAmount{9'999'999'9995, -4})); + } }, std::nullopt, 0, @@ -2670,11 +2710,15 @@ private: fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct); ammAlice.deposit(bob, 1'000'000); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(12'000), USD(12'000), IOUAmount{12'000'000, 0})); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{12'000'000'001}, USD(12'000), IOUAmount{12'000'000, 0})); + } // Initial state. Pay bidMin. env(ammAlice.bid({.account = carol, .bidMin = 110})).close(); @@ -2701,11 +2745,15 @@ private: BEAST_EXPECT(ammAlice.expectAuctionSlot(0, std::nullopt, IOUAmount{110})); // ~321.09 tokens burnt on bidding fees. if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(12'000), USD(12'000), IOUAmount{11'999'678'91, -2})); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{12'000'000'001}, USD(12'000), IOUAmount{11'999'678'91, -2})); + } }, std::nullopt, 0, @@ -2735,10 +2783,14 @@ private: ammTokens -= slotPrice; BEAST_EXPECT(ammAlice.expectAuctionSlot(100, 0, slotPrice)); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances(XRP(13'000), USD(13'000), ammTokens)); + } else + { BEAST_EXPECT( ammAlice.expectBalances(XRPAmount{13'000'000'003}, USD(13'000), ammTokens)); + } // Discounted trade for (int i = 0; i < 10; ++i) { @@ -2774,15 +2826,19 @@ private: env.balance(ed, USD) == STAmount(USD, UINT64_C(18'999'0057261184), -10)); // USD pool is slightly higher because of the fees. if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(13'000), STAmount(USD, UINT64_C(13'002'98282151422), -11), ammTokens)); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'003}, STAmount(USD, UINT64_C(13'002'98282151422), -11), ammTokens)); + } } ammTokens = ammAlice.getLPTokensBalance(); // Trade with the fee @@ -2818,51 +2874,67 @@ private: else { if (!features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(dan, USD) == STAmount(USD, UINT64_C(19'490'05672274399), -11)); + } else + { BEAST_EXPECT( env.balance(dan, USD) == STAmount(USD, UINT64_C(19'490'05672274398), -11)); + } // USD pool gains more in dan's fees. if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(13'000), STAmount{USD, UINT64_C(13'012'92609877023), -11}, ammTokens)); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'003}, STAmount{USD, UINT64_C(13'012'92609877024), -11}, ammTokens)); + } // Discounted fee payment ammAlice.deposit(carol, USD(100)); ammTokens = ammAlice.getLPTokensBalance(); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(13'000), STAmount{USD, UINT64_C(13'112'92609877023), -11}, ammTokens)); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'003}, STAmount{USD, UINT64_C(13'112'92609877024), -11}, ammTokens)); + } env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); env.close(); // carol pays 100000 drops in fees // 99900668XRP swapped in for 100USD if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'100'000'668}, STAmount{USD, UINT64_C(13'012'92609877023), -11}, ammTokens)); + } else + { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'100'000'671}, STAmount{USD, UINT64_C(13'012'92609877024), -11}, ammTokens)); + } } // Payment with the trading fee env(pay(alice, carol, XRP(100)), path(~XRP), sendmax(USD(110))); @@ -2896,13 +2968,17 @@ private: // clock is parent's based env.close(); if (!features[fixAMMv1_1]) + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(29'399'00572620545), -11)); + } else if (!features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(29'399'00572620544), -11)); + } ammTokens = ammAlice.getLPTokensBalance(); for (int i = 0; i < 10; ++i) { @@ -4397,17 +4473,21 @@ private: prep( [&](Env& env) { if (!features[fixAMMv1_1]) + { env(offer( LP1, XRPAmount{18'095'133}, STAmount{TST, UINT64_C(1'68737984885388), -14}), txflags(tfPassive)); + } else + { env(offer( LP1, XRPAmount{18'095'132}, STAmount{TST, UINT64_C(1'68737976189735), -14}), txflags(tfPassive)); + } }, [&](Env& env) { BEAST_EXPECT( @@ -4528,11 +4608,15 @@ private: // carol withdraws ~1,443.44USD auto const balanceAfterWithdraw = [&]() { if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) + { return STAmount(USD, UINT64_C(30'443'43891402715), -11); - else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + } + if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + { return STAmount(USD, UINT64_C(30'443'43891402714), -11); - else - return STAmount(USD, UINT64_C(30'443'43891402713), -11); + } + + return STAmount(USD, UINT64_C(30'443'43891402713), -11); }(); BEAST_EXPECT(env.balance(carol, USD) == balanceAfterWithdraw); // Set to original pool size @@ -4543,25 +4627,37 @@ private: BEAST_EXPECT(ammAlice.expectTradingFee(0)); auto const tokensNoFee = ammAlice.withdraw(carol, deposit); if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(30'443'43891402717), -11)); + } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(30'443'43891402716), -11)); + } else + { BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(30'443'43891402713), -11)); + } // carol pays ~4008 LPTokens in fees or ~0.5% of the no-fee // LPTokens if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779913, -8)); + } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779912, -8)); + } else + { BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779911, -8)); + } BEAST_EXPECT(tokensFee == IOUAmount(750'588'23529411, -8)); }, std::nullopt, @@ -4808,49 +4904,73 @@ private: // other have a tiny loss. The last account to withdraw // gets everything in the pool. if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(10'000), STAmount{USD, UINT64_C(10'000'0000000013), -10}, IOUAmount{10'000'000})); + } else if (features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectBalances( XRP(10'000), STAmount{USD, UINT64_C(10'000'0000000003), -10}, IOUAmount{10'000'000})); + } else + { BEAST_EXPECT( ammAlice.expectBalances(XRP(10'000), USD(10'000), IOUAmount{10'000'000})); + } BEAST_EXPECT(expectHolding(env, ben, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, simon, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, chris, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, dan, USD(1'500'000))); if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(expectHolding( env, carol, STAmount{USD, UINT64_C(30'000'00000000001), -11})); + } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); + } else + { BEAST_EXPECT(expectHolding(env, carol, USD(30'000))); + } BEAST_EXPECT(expectHolding(env, ed, USD(1'500'000))); BEAST_EXPECT(expectHolding(env, paul, USD(1'500'000))); if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(expectHolding( env, natalie, STAmount{USD, UINT64_C(1'500'000'000000002), -9})); + } else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + { BEAST_EXPECT(expectHolding( env, natalie, STAmount{USD, UINT64_C(1'500'000'000000005), -9})); + } else + { BEAST_EXPECT(expectHolding(env, natalie, USD(1'500'000))); + } ammAlice.withdrawAll(alice); BEAST_EXPECT(!ammAlice.ammExists()); if (!features[fixAMMv1_1]) + { BEAST_EXPECT( expectHolding(env, alice, STAmount{USD, UINT64_C(30'000'0000000013), -10})); + } else if (features[fixAMMv1_3]) + { BEAST_EXPECT( expectHolding(env, alice, STAmount{USD, UINT64_C(30'000'0000000003), -10})); + } else + { BEAST_EXPECT(expectHolding(env, alice, USD(30'000))); + } // alice XRP balance is 30,000 initial - 50 AMMCreate fee - // 10drops fee BEAST_EXPECT( @@ -5252,6 +5372,7 @@ private: if (rates.first == 1.5) { if (!features[fixAMMv1_1]) + { BEAST_EXPECT(expectOffers( env, ed, @@ -5259,7 +5380,9 @@ private: {{Amounts{ STAmount{ETH, UINT64_C(378'6327949540823), -13}, STAmount{USD, UINT64_C(283'9745962155617), -13}}}})); + } else + { BEAST_EXPECT(expectOffers( env, ed, @@ -5267,10 +5390,12 @@ private: {{Amounts{ STAmount{ETH, UINT64_C(378'6327949540813), -13}, STAmount{USD, UINT64_C(283'974596215561), -12}}}})); + } } else { if (!features[fixAMMv1_1]) + { BEAST_EXPECT(expectOffers( env, ed, @@ -5278,7 +5403,9 @@ private: {{Amounts{ STAmount{ETH, UINT64_C(325'299461620749), -12}, STAmount{USD, UINT64_C(243'9745962155617), -13}}}})); + } else + { BEAST_EXPECT(expectOffers( env, ed, @@ -5286,6 +5413,7 @@ private: {{Amounts{ STAmount{ETH, UINT64_C(325'299461620748), -12}, STAmount{USD, UINT64_C(243'974596215561), -12}}}})); + } } } else if (i == 2) @@ -5701,18 +5829,26 @@ private: if (status == SucceedShouldSucceedResize) { if (!features[fixAMMv1_1]) + { BEAST_EXPECT(Quality{*amounts} < quality); + } else + { BEAST_EXPECT(Quality{*amounts} >= quality); + } } else if (status == Succeed) { if (!features[fixAMMv1_1]) + { BEAST_EXPECT( Quality{*amounts} >= quality || withinRelativeDistance(Quality{*amounts}, quality, Number{1, -7})); + } else + { BEAST_EXPECT(Quality{*amounts} >= quality); + } } else if (status == FailShouldSucceed) { @@ -5741,7 +5877,7 @@ private: takerPays, swapAssetIn(Amounts{poolIn, poolOut}, takerPays, tfee)}; } - else if (isXRP(poolOut)) + if (isXRP(poolOut)) { auto const takerGets = STAmount{xrpIssue(), 1}; return Amounts{ @@ -5871,7 +6007,7 @@ private: STAmount const goodUsdBIT; STAmount const goodUsdBITr; IOUAmount const lpTokenBalance; - std::optional const lpTokenBalanceAlt = {}; + std::optional const lpTokenBalanceAlt = std::nullopt; double const offer1BtcGH = 0.1; double const offer2BtcGH = 0.1; double const offer2UsdGH = 1; @@ -6640,9 +6776,13 @@ private: amm.withdraw(WithdrawArg{.asset1Out = STAmount{XPM, 1, -5}}); auto const [amount_, amount2_, lptAMM_] = amm.balances(XRP, XPM); if (!env.enabled(fixAMMv1_3)) + { BEAST_EXPECT((amount2 - amount2_) > withdraw); + } else + { BEAST_EXPECT((amount2 - amount2_) <= withdraw); + } }, 0); } @@ -6657,9 +6797,13 @@ private: auto const res = root2(amount * amount2); if (shouldFail) + { BEAST_EXPECT(res < lptBalance); + } else + { BEAST_EXPECT(res >= lptBalance); + } } void diff --git a/src/test/app/AccountSet_test.cpp b/src/test/app/AccountSet_test.cpp index 87c6474be2..73e807a8aa 100644 --- a/src/test/app/AccountSet_test.cpp +++ b/src/test/app/AccountSet_test.cpp @@ -307,9 +307,13 @@ public: // If the field is not present expect the default value if (!(*env.le(alice))[~sfTransferRate]) + { BEAST_EXPECT(r.get == 1.0); + } else + { BEAST_EXPECT(*(*env.le(alice))[~sfTransferRate] == r.get * QUALITY_ONE); + } } }; diff --git a/src/test/app/AmendmentTable_test.cpp b/src/test/app/AmendmentTable_test.cpp index 3b14c8b622..d8431e5696 100644 --- a/src/test/app/AmendmentTable_test.cpp +++ b/src/test/app/AmendmentTable_test.cpp @@ -390,7 +390,7 @@ public: { uint256 const supportedID = amendmentId(a); bool const enabled = table->isEnabled(supportedID); - bool const found = allEnabled.find(supportedID) != allEnabled.end(); + bool const found = allEnabled.contains(supportedID); BEAST_EXPECTS( enabled == found, a + (enabled ? " enabled " : " disabled ") + (found ? " found" : " not found")); @@ -404,7 +404,7 @@ public: std::vector const desired = table->getDesired(); for (uint256 const& a : desired) - BEAST_EXPECT(vetoed.count(a) == 0); + BEAST_EXPECT(not vetoed.contains(a)); // Unveto an amendment that is already not vetoed. Shouldn't // hurt anything, but the values returned by getDesired() @@ -526,22 +526,22 @@ public: { case 0: // amendment goes from majority to enabled - if (enabled.find(hash) != enabled.end()) + if (enabled.contains(hash)) Throw("enabling already enabled"); - if (majority.find(hash) == majority.end()) + if (!majority.contains(hash)) Throw("enabling without majority"); enabled.insert(hash); majority.erase(hash); break; case tfGotMajority: - if (majority.find(hash) != majority.end()) + if (majority.contains(hash)) Throw("got majority while having majority"); majority[hash] = roundTime; break; case tfLostMajority: - if (majority.find(hash) == majority.end()) + if (!majority.contains(hash)) Throw("lost majority without majority"); majority.erase(hash); break; @@ -719,7 +719,7 @@ public: BEAST_EXPECT(ourVotes.size() == yes_.size()); BEAST_EXPECT(enabled.empty()); for (auto const& i : yes_) - BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end()); + BEAST_EXPECT(not majority.contains(amendmentId(i))); // Now, everyone votes for this feature for (auto const& i : yes_) @@ -766,7 +766,7 @@ public: BEAST_EXPECT(enabled.size() == yes_.size()); BEAST_EXPECT(ourVotes.empty()); for (auto const& i : yes_) - BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end()); + BEAST_EXPECT(not majority.contains(amendmentId(i))); } // Detect majority at 80%, enable later diff --git a/src/test/app/Check_test.cpp b/src/test/app/Check_test.cpp index 00e8dd4d53..f8bb0ddcf2 100644 --- a/src/test/app/Check_test.cpp +++ b/src/test/app/Check_test.cpp @@ -528,8 +528,8 @@ class Check_test : public beast::unit_test::suite env.close(); env.require(balance(alice, startBalance - XRP(10) - drops(baseFeeDrops))); env.require(balance(bob, startBalance + XRP(10) - drops(baseFeeDrops))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 0); BEAST_EXPECT(ownerCount(env, bob) == 0); @@ -562,8 +562,8 @@ class Check_test : public beast::unit_test::suite verifyDeliveredAmount(env, drops(checkAmount.mantissa())); env.require(balance(alice, reserve)); env.require(balance(bob, startBalance + checkAmount - drops(baseFeeDrops * 3))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 0); BEAST_EXPECT(ownerCount(env, bob) == 0); @@ -592,8 +592,8 @@ class Check_test : public beast::unit_test::suite verifyDeliveredAmount(env, drops(checkAmount.mantissa() - 1)); env.require(balance(alice, reserve)); env.require(balance(bob, startBalance + checkAmount - drops(baseFeeDrops * 2 + 1))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 0); BEAST_EXPECT(ownerCount(env, bob) == 0); @@ -663,8 +663,8 @@ class Check_test : public beast::unit_test::suite env.close(); env.require(balance(alice, USD(0))); env.require(balance(bob, USD(10))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); BEAST_EXPECT(ownerCount(env, bob) == 1); @@ -688,8 +688,8 @@ class Check_test : public beast::unit_test::suite env.close(); env.require(balance(alice, USD(2))); env.require(balance(bob, USD(8))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); BEAST_EXPECT(ownerCount(env, bob) == 1); @@ -755,8 +755,8 @@ class Check_test : public beast::unit_test::suite env.close(); env.require(balance(alice, USD(0))); env.require(balance(bob, USD(10))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); BEAST_EXPECT(ownerCount(env, bob) == 1); } @@ -838,8 +838,8 @@ class Check_test : public beast::unit_test::suite verifyDeliveredAmount(env, USD(2)); env.require(balance(alice, USD(0))); env.require(balance(bob, USD(8))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); BEAST_EXPECT(ownerCount(env, bob) == 1); } @@ -890,8 +890,8 @@ class Check_test : public beast::unit_test::suite env.require(balance(alice, USD(8) - bobGot)); env.require(balance(bob, bobGot)); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); BEAST_EXPECT(ownerCount(env, bob) == 1); } @@ -945,8 +945,8 @@ class Check_test : public beast::unit_test::suite env.close(); env.require(balance(alice, USD(5))); env.require(balance(bob, USD(3))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); BEAST_EXPECT(ownerCount(env, bob) == 2); } @@ -1018,8 +1018,8 @@ class Check_test : public beast::unit_test::suite env.close(); env.require(balance(alice, USD(1000 - 125 - 60))); env.require(balance(bob, USD(0 + 100 + 50))); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); - BEAST_EXPECT(checksOnAccount(env, bob).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); + BEAST_EXPECT(checksOnAccount(env, bob).empty()); } void @@ -1655,7 +1655,7 @@ class Check_test : public beast::unit_test::suite env(check::cancel(bob, chkIdNotExp3)); env.close(); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); BEAST_EXPECT(ownerCount(env, alice) == 1); } } @@ -1815,7 +1815,7 @@ class Check_test : public beast::unit_test::suite env.require(owners(alice, 6)); env.require(tickets(alice, env.seq(alice) - aliceTicketSeq)); - BEAST_EXPECT(checksOnAccount(env, alice).size() == 0); + BEAST_EXPECT(checksOnAccount(env, alice).empty()); BEAST_EXPECT(env.seq(alice) == aliceSeq); env.require(balance(alice, USD(700))); @@ -1852,7 +1852,7 @@ class Check_test : public beast::unit_test::suite } // Operators to make using the class more convenient. - operator Account const() const + operator Account() const { return acct; } diff --git a/src/test/app/DNS_test.cpp b/src/test/app/DNS_test.cpp index 0c2946f8ed..9b75e66b85 100644 --- a/src/test/app/DNS_test.cpp +++ b/src/test/app/DNS_test.cpp @@ -15,7 +15,7 @@ class DNS_test : public beast::unit_test::suite using endpoint_type = boost::asio::ip::tcp::endpoint; using error_code = boost::system::error_code; std::weak_ptr work_; - endpoint_type lastEndpoint_{}; + endpoint_type lastEndpoint_; parsedURL pUrl_; std::string port_; jtx::Env env_; @@ -76,7 +76,7 @@ public: parse() { std::string url = arg(); - if (url == "") + if (url.empty()) url = "https://vl.ripple.com"; BEAST_EXPECT(parseUrl(pUrl_, url)); port_ = pUrl_.port ? std::to_string(*pUrl_.port) : "443"; diff --git a/src/test/app/DepositAuth_test.cpp b/src/test/app/DepositAuth_test.cpp index 547d9d8b62..ad401499bc 100644 --- a/src/test/app/DepositAuth_test.cpp +++ b/src/test/app/DepositAuth_test.cpp @@ -1283,8 +1283,10 @@ struct DepositPreauth_test : public beast::unit_test::suite auto issuer = c[jss::Issuer].asString(); if (BEAST_EXPECT(pubKey2Acc.contains(issuer))) + { readCreds.emplace_back( pubKey2Acc.at(issuer), c["CredentialType"].asString()); + } } BEAST_EXPECT(std::ranges::is_sorted(readCreds)); diff --git a/src/test/app/Discrepancy_test.cpp b/src/test/app/Discrepancy_test.cpp index 08a8a01753..3f808b37d8 100644 --- a/src/test/app/Discrepancy_test.cpp +++ b/src/test/app/Discrepancy_test.cpp @@ -93,11 +93,17 @@ class Discrepancy_test : public beast::unit_test::suite { Json::Value node; if (an.isMember(sfCreatedNode.fieldName)) + { node = an[sfCreatedNode.fieldName]; + } else if (an.isMember(sfModifiedNode.fieldName)) + { node = an[sfModifiedNode.fieldName]; + } else if (an.isMember(sfDeletedNode.fieldName)) + { node = an[sfDeletedNode.fieldName]; + } if (node && node[sfLedgerEntryType.fieldName] == jss::AccountRoot) { @@ -108,11 +114,15 @@ class Discrepancy_test : public beast::unit_test::suite ? node[sfFinalFields.fieldName] : node[sfNewFields.fieldName]; if (prevFields) + { sumPrev += beast::lexicalCastThrow( prevFields[sfBalance.fieldName].asString()); + } if (finalFields) + { sumFinal += beast::lexicalCastThrow( finalFields[sfBalance.fieldName].asString()); + } } } // the difference in balances (final and prev) should be the diff --git a/src/test/app/EscrowToken_test.cpp b/src/test/app/EscrowToken_test.cpp index 5cbeb0b94a..280356c494 100644 --- a/src/test/app/EscrowToken_test.cpp +++ b/src/test/app/EscrowToken_test.cpp @@ -1258,9 +1258,13 @@ struct EscrowToken_test : public beast::unit_test::suite env.close(); if (t.hasTrustline) + { env.trust(USD(100'000), t.src, t.dst); + } else + { env.trust(USD(100'000), t.src); + } env.close(); env(pay(t.gw, t.src, USD(10'000))); diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index c56cef39f8..692d9d2b50 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -196,6 +196,7 @@ struct Flow_test : public beast::unit_test::suite // Dan -> Bob -> Alice -> Carol; vary bobDanQIn and bobAliceQOut for (auto bobDanQIn : {80, 100, 120}) + { for (auto bobAliceQOut : {80, 100, 120}) { Env env(*this, features); @@ -213,12 +214,17 @@ struct Flow_test : public beast::unit_test::suite txflags(tfNoRippleDirect)); env.require(balance(bob, USDA(90))); if (bobAliceQOut > bobDanQIn) + { env.require( balance(bob, USDD(10.0 * double(bobAliceQOut) / double(bobDanQIn)))); + } else + { env.require(balance(bob, USDD(10))); + } env.require(balance(carol, USDA(10))); } + } // bob -> alice -> carol; vary carolAliceQIn for (auto carolAliceQIn : {80, 100, 120}) @@ -472,8 +478,10 @@ struct Flow_test : public beast::unit_test::suite return false; Sandbox sb(&view, tapNONE); for (auto const& o : flowResult.removableOffers) + { if (auto ok = sb.peek(keylet::offer(o))) offerDelete(sb, ok, flowJournal); + } sb.apply(view); return true; }); diff --git a/src/test/app/HashRouter_test.cpp b/src/test/app/HashRouter_test.cpp index 43ef4a4e06..58bace3ef2 100644 --- a/src/test/app/HashRouter_test.cpp +++ b/src/test/app/HashRouter_test.cpp @@ -231,7 +231,7 @@ class HashRouter_test : public beast::unit_test::suite ++stopwatch; // Confirm that peers list is empty. peers = router.shouldRelay(key1); - BEAST_EXPECT(peers && peers->size() == 0); + BEAST_EXPECT(peers && peers->empty()); } void diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index 3101fda316..e17ef1fd55 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -71,7 +71,7 @@ class Invariants_test : public beast::unit_test::suite Preclose const& preclose = {}, TxAccount setTxAccount = TxAccount::None) { - return doInvariantCheck( + doInvariantCheck( test::jtx::Env(*this, defaultAmendments()), expect_logs, precheck, @@ -105,7 +105,7 @@ class Invariants_test : public beast::unit_test::suite if (setTxAccount != TxAccount::None) tx.setAccountID(sfAccount, setTxAccount == TxAccount::A1 ? A1.id() : A2.id()); - return doInvariantCheck(std::move(env), A1, A2, expect_logs, precheck, fee, tx, ters); + doInvariantCheck(std::move(env), A1, A2, expect_logs, precheck, fee, tx, ters); } void @@ -395,22 +395,21 @@ class Invariants_test : public beast::unit_test::suite for (auto const& trustKeylet : {keylet::line(ammAcctID, A1["USD"]), keylet::line(A1, ammIssue)}) { - if (auto const line = ac.view().peek(trustKeylet); !line) + auto const line = ac.view().peek(trustKeylet); + if (!line) { return false; } - else - { - STAmount const lowLimit = line->at(sfLowLimit); - STAmount const highLimit = line->at(sfHighLimit); - BEAST_EXPECT( - trustDelete( - ac.view(), - line, - lowLimit.getIssuer(), - highLimit.getIssuer(), - ac.journal) == tesSUCCESS); - } + + STAmount const lowLimit = line->at(sfLowLimit); + STAmount const highLimit = line->at(sfHighLimit); + BEAST_EXPECT( + trustDelete( + ac.view(), + line, + lowLimit.getIssuer(), + highLimit.getIssuer(), + ac.journal) == tesSUCCESS); } auto const ammSle = ac.view().peek(keylet::amm(ammKey)); @@ -2262,14 +2261,16 @@ class Invariants_test : public beast::unit_test::suite }; struct Adjustments { - std::optional assetsTotal = {}; - std::optional assetsAvailable = {}; - std::optional lossUnrealized = {}; - std::optional assetsMaximum = {}; - std::optional sharesTotal = {}; - std::optional vaultAssets = {}; - std::optional accountAssets = {}; - std::optional accountShares = {}; + // NOLINTBEGIN(readability-redundant-member-init) + std::optional assetsTotal = std::nullopt; + std::optional assetsAvailable = std::nullopt; + std::optional lossUnrealized = std::nullopt; + std::optional assetsMaximum = std::nullopt; + std::optional sharesTotal = std::nullopt; + std::optional vaultAssets = std::nullopt; + std::optional accountAssets = std::nullopt; + std::optional accountShares = std::nullopt; + // NOLINTEND(readability-redundant-member-init) }; auto constexpr adjust = [&](ApplyView& ac, xrpl::Keylet keylet, Adjustments args) { auto sleVault = ac.peek(keylet); @@ -2291,8 +2292,10 @@ class Invariants_test : public beast::unit_test::suite if (args.assetsTotal) (*sleVault)[sfAssetsTotal] = *(*sleVault)[sfAssetsTotal] + *args.assetsTotal; if (args.assetsAvailable) + { (*sleVault)[sfAssetsAvailable] = *(*sleVault)[sfAssetsAvailable] + *args.assetsAvailable; + } ac.update(sleVault); if (args.sharesTotal) @@ -2325,7 +2328,9 @@ class Invariants_test : public beast::unit_test::suite ac.update(sleMPToken); } else + { return false; // Not supporting testing with IOU + } } if (args.accountAssets) @@ -2349,7 +2354,9 @@ class Invariants_test : public beast::unit_test::suite ac.update(sleMPToken); } else + { return false; // Not supporting testing with IOU + } } if (args.accountShares) diff --git a/src/test/app/LPTokenTransfer_test.cpp b/src/test/app/LPTokenTransfer_test.cpp index 15a8837c4f..265ff7d2ef 100644 --- a/src/test/app/LPTokenTransfer_test.cpp +++ b/src/test/app/LPTokenTransfer_test.cpp @@ -299,9 +299,13 @@ class LPTokenTransfer_test : public jtx::AMMTest // with fixFrozenLPTokenTransfer enabled, bob fails to cash the check if (features[fixFrozenLPTokenTransfer]) + { env(check::cash(bob, carolChkId, STAmount{lpIssue, 10}), ter(tecPATH_PARTIAL)); + } else + { env(check::cash(bob, carolChkId, STAmount{lpIssue, 10})); + } env.close(); diff --git a/src/test/app/LedgerLoad_test.cpp b/src/test/app/LedgerLoad_test.cpp index 4c0cb00f3f..46c372923e 100644 --- a/src/test/app/LedgerLoad_test.cpp +++ b/src/test/app/LedgerLoad_test.cpp @@ -36,17 +36,19 @@ class LedgerLoad_test : public beast::unit_test::suite struct SetupData { std::string const dbPath; - std::string ledgerFile{}; - Json::Value ledger{}; - Json::Value hashes{}; - uint256 trapTxHash{}; + // NOLINTBEGIN(readability-redundant-member-init) + std::string ledgerFile = {}; + Json::Value ledger = {}; + Json::Value hashes = {}; + uint256 trapTxHash = {}; + // NOLINTEND(readability-redundant-member-init) }; SetupData setupLedger(beast::temp_dir const& td) { using namespace test::jtx; - SetupData retval = {td.path()}; + SetupData retval = {.dbPath = td.path()}; retval.ledgerFile = td.file("ledgerdata.json"); diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp index 4428e82ea9..54c12b465a 100644 --- a/src/test/app/LedgerReplay_test.cpp +++ b/src/test/app/LedgerReplay_test.cpp @@ -355,9 +355,13 @@ struct TestPeerSet : public PeerSet { int dropRate = 0; if (behavior == PeerSetBehavior::Drop50) + { dropRate = 50; + } else if (behavior == PeerSetBehavior::DropAll) + { dropRate = 100; + } if ((rand() % 100 + 1) <= dropRate) return; @@ -497,7 +501,7 @@ struct LedgerServer auto updateIdx = [&]() { assert(fundedAccounts > senders.size()); fromIdx = (fromIdx + r) % fundedAccounts; - while (senders.count(fromIdx) != 0) + while (senders.contains(fromIdx)) fromIdx = (fromIdx + 1) % fundedAccounts; senders.insert(fromIdx); toIdx = (toIdx + r * 2) % fundedAccounts; @@ -968,7 +972,7 @@ struct LedgerReplayer_test : public beast::unit_test::suite { testcase("TaskParameter"); - auto makeSkipList = [](int count) -> std::vector const { + auto makeSkipList = [](int count) -> std::vector { std::vector sList; for (int i = 0; i < count; ++i) sList.emplace_back(i); @@ -1095,7 +1099,9 @@ struct LedgerReplayer_test : public beast::unit_test::suite l = net.server.ledgerMaster.getLedgerByHash(l->header().parentHash); } else + { break; + } } net.client.replayer.replay(InboundLedger::Reason::GENERIC, finalHash, totalReplay); diff --git a/src/test/app/LoanBroker_test.cpp b/src/test/app/LoanBroker_test.cpp index 380035167c..361f70209f 100644 --- a/src/test/app/LoanBroker_test.cpp +++ b/src/test/app/LoanBroker_test.cpp @@ -91,12 +91,24 @@ class LoanBroker_test : public beast::unit_test::suite { { auto const& asset = vault.asset.raw(); - testcase << "Lifecycle: " - << (asset.native() ? "XRP " - : asset.holds() ? "IOU " - : asset.holds() ? "MPT " - : "Unknown ") - << label; + std::string_view assetLabel; + if (asset.native()) + { + assetLabel = "XRP "; + } + else if (asset.holds()) + { + assetLabel = "IOU "; + } + else if (asset.holds()) + { + assetLabel = "MPT "; + } + else + { + assetLabel = "Unknown "; + } + testcase << "Lifecycle: " << assetLabel << label; } using namespace jtx; @@ -877,8 +889,10 @@ class LoanBroker_test : public beast::unit_test::suite env(coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)), ter(tecFROZEN)); } else + { // Fund the cover deposit env(coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10))); + } env.close(); if (brokerTest == CoverWithdraw) @@ -999,7 +1013,9 @@ class LoanBroker_test : public beast::unit_test::suite env(del(alice, brokerKeylet.key), ter(tesSUCCESS)); } else + { env(del(alice, brokerKeylet.key)); + } if (brokerTest == Set) { diff --git a/src/test/app/Loan_test.cpp b/src/test/app/Loan_test.cpp index f1cd76d88b..171e2eddb5 100644 --- a/src/test/app/Loan_test.cpp +++ b/src/test/app/Loan_test.cpp @@ -81,7 +81,7 @@ protected: int coverDeposit = 1000; TenthBips16 managementFeeRate{100}; TenthBips32 coverRateLiquidation = percentageToTenthBips(25); - std::string data{}; + std::string data = {}; // NOLINT(readability-redundant-member-init) std::uint32_t flags = 0; Number @@ -150,20 +150,22 @@ protected: // only signs. bool counterpartyExplicit = true; Number principalRequest; - std::optional setFee{}; - std::optional originationFee{}; - std::optional serviceFee{}; - std::optional lateFee{}; - std::optional closeFee{}; - std::optional overFee{}; - std::optional interest{}; - std::optional lateInterest{}; - std::optional closeInterest{}; - std::optional overpaymentInterest{}; - std::optional payTotal{}; - std::optional payInterval{}; - std::optional gracePd{}; - std::optional flags{}; + // NOLINTBEGIN(readability-redundant-member-init) + std::optional setFee = std::nullopt; + std::optional originationFee = std::nullopt; + std::optional serviceFee = std::nullopt; + std::optional lateFee = std::nullopt; + std::optional closeFee = std::nullopt; + std::optional overFee = std::nullopt; + std::optional interest = std::nullopt; + std::optional lateInterest = std::nullopt; + std::optional closeInterest = std::nullopt; + std::optional overpaymentInterest = std::nullopt; + std::optional payTotal = std::nullopt; + std::optional payInterval = std::nullopt; + std::optional gracePd = std::nullopt; + std::optional flags = std::nullopt; + // NOLINTEND(readability-redundant-member-init) template jtx::JTx @@ -232,7 +234,7 @@ protected: struct LoanState { std::uint32_t previousPaymentDate = 0; - NetClock::time_point startDate = {}; + NetClock::time_point startDate; std::uint32_t nextPaymentDate = 0; std::uint32_t paymentRemaining = 0; std::int32_t const loanScale = 0; @@ -698,10 +700,12 @@ protected: env.close(); if (asset.native() || lender != issuer) + { env( pay((asset.native() ? env.master : issuer), lender, asset(brokerParams.vaultDeposit + brokerParams.coverDeposit))); + } // Fund the borrower later once we know the total loan // size @@ -773,10 +777,12 @@ protected: auto const shortage = totalNeeded - borrowerBalance.number(); if (shortage > beast::zero && (broker.asset.native() || issuer != borrower)) + { env( pay((broker.asset.native() ? env.master : issuer), borrower, STAmount{broker.asset, shortage})); + } } void @@ -826,6 +832,7 @@ protected: roundPeriodicPayment(broker.asset, state.periodicPayment, state.loanScale)}; if (!showStepBalances) + { log << currencyLabel << " Payment components: " << "Payments remaining, " << "rawInterest, rawPrincipal, " @@ -833,6 +840,7 @@ protected: << "trackedValueDelta, trackedPrincipalDelta, " "trackedInterestDelta, trackedMgmtFeeDelta, special" << std::endl; + } // Include the service fee STAmount const totalDue = @@ -947,18 +955,21 @@ protected: (state.loanScale - (deltas.total() - state.periodicPayment).exponent()) > 14); if (!showStepBalances) + { log << currencyLabel << " Payment components: " << state.paymentRemaining << ", " << deltas.interest << ", " << deltas.principal << ", " << deltas.managementFee << ", " << paymentComponents.trackedValueDelta << ", " << paymentComponents.trackedPrincipalDelta << ", " << paymentComponents.trackedInterestPart() << ", " - << paymentComponents.trackedManagementFeeDelta << ", " - << (paymentComponents.specialCase == detail::PaymentSpecialCase::final ? "final" - : paymentComponents.specialCase == detail::PaymentSpecialCase::extra - ? "extra" - : "none") - << std::endl; + << paymentComponents.trackedManagementFeeDelta << ", " << [&]() -> char const* { + if (paymentComponents.specialCase == detail::PaymentSpecialCase::final) + return "final"; + if (paymentComponents.specialCase == detail::PaymentSpecialCase::extra) + return "extra"; + return "none"; + }() << std::endl; + } auto const totalDueAmount = STAmount{broker.asset, paymentComponents.trackedValueDelta + serviceFee}; @@ -1016,8 +1027,10 @@ protected: { auto const loanSle = env.le(loanKeylet); if (!BEAST_EXPECT(loanSle)) + { // No reason for this not to exist return; + } auto const current = constructRoundedLoanState(loanSle); auto const errors = nextTrueState - current; log << currencyLabel << " Loan balances: " @@ -1091,8 +1104,10 @@ protected: { auto const loanSle = env.le(loanKeylet); if (!BEAST_EXPECT(loanSle)) + { // No reason for this not to exist return; + } log << currencyLabel << " Total amounts paid: " << "\n\tTotal value: " << totalPaid.trackedValueDelta << " (initial: " << truncate(initialState.totalValue) @@ -1179,8 +1194,10 @@ protected: auto const [keylet, loanSequence] = [&]() { auto const brokerSle = env.le(keylet::loanbroker(broker.brokerID)); if (!BEAST_EXPECT(brokerSle)) + { // will be invalid return std::make_pair(keylet::loan(broker.brokerID), std::uint32_t(0)); + } // Broker has no loans BEAST_EXPECT(brokerSle->at(sfOwnerCount) == 0); @@ -1454,11 +1471,13 @@ protected: std::string getCurrencyLabel(Asset const& asset) { - return ( - asset.native() ? "XRP" - : asset.holds() ? "IOU" - : asset.holds() ? "MPT" - : "Unknown"); + if (asset.native()) + return "XRP"; + if (asset.holds()) + return "IOU"; + if (asset.holds()) + return "MPT"; + return "Unknown"; } /** Wrapper to run a series of lifecycle tests for a given asset and loan @@ -1788,8 +1807,10 @@ protected: auto const vaultPseudo = [&]() { auto const vaultSle = env.le(keylet::vault(brokerSle->at(sfVaultID))); if (!BEAST_EXPECT(vaultSle)) + { // This will be wrong, but the test has failed anyway. return lender; + } auto const vaultPseudo = Account("Vault pseudo-account", vaultSle->at(sfAccount)); return vaultPseudo; }(); @@ -1807,7 +1828,7 @@ protected: // XRP can't be frozen return std::make_tuple(empty, empty, empty, tesSUCCESS); } - else if (broker.asset.holds()) + if (broker.asset.holds()) { auto freeze = [&](Account const& holder) { env(trust(issuer, holder[iouCurrency](0), tfSetFreeze)); @@ -1821,16 +1842,14 @@ protected: }; return std::make_tuple(freeze, deepfreeze, unfreeze, tecFROZEN); } - else - { - auto freeze = [&](Account const& holder) { - mptt.set({.account = issuer, .holder = holder, .flags = tfMPTLock}); - }; - auto unfreeze = [&](Account const& holder) { - mptt.set({.account = issuer, .holder = holder, .flags = tfMPTUnlock}); - }; - return std::make_tuple(freeze, empty, unfreeze, tecLOCKED); - } + + auto freeze = [&](Account const& holder) { + mptt.set({.account = issuer, .holder = holder, .flags = tfMPTLock}); + }; + auto unfreeze = [&](Account const& holder) { + mptt.set({.account = issuer, .holder = holder, .flags = tfMPTUnlock}); + }; + return std::make_tuple(freeze, empty, unfreeze, tecLOCKED); }(); // Try freezing the accounts that can't be frozen @@ -2511,12 +2530,13 @@ protected: << ", " << paymentComponents.trackedPrincipalDelta << ", " << paymentComponents.trackedInterestPart() << ", " << paymentComponents.trackedManagementFeeDelta << ", " - << (paymentComponents.specialCase == detail::PaymentSpecialCase::final - ? "final" - : paymentComponents.specialCase == - detail::PaymentSpecialCase::extra - ? "extra" - : "none"); + << [&]() -> char const* { + if (paymentComponents.specialCase == detail::PaymentSpecialCase::final) + return "final"; + if (paymentComponents.specialCase == detail::PaymentSpecialCase::extra) + return "extra"; + return "none"; + }(); auto const totalDueAmount = STAmount{ broker.asset, paymentComponents.trackedValueDelta + serviceFee.number()}; @@ -2568,8 +2588,10 @@ protected: auto const borrowerBalanceBeforePayment = env.balance(borrower, broker.asset); if (canImpairLoan(env, broker, state)) + { // Making a payment will unimpair the loan env(manage(lender, loanKeylet.key, tfLoanImpair)); + } env.close(); @@ -4247,10 +4269,8 @@ protected: { return Account{"pseudo", brokerSle->at(sfAccount)}; } - else - { - return std::nullopt; - } + + return std::nullopt; }(); if (!pseudoBroker) return; @@ -6247,9 +6267,13 @@ protected: Vault vault(env); if (borrower == broker) + { env.fund(XRP(10'000), broker, issuer, depositor); + } else + { env.fund(XRP(10'000), broker, borrower, issuer, depositor); + } env.close(); auto const xrpFee = XRP(100); diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 5a46331aa9..5a90a3a71e 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -1840,11 +1840,17 @@ class MPToken_test : public beast::unit_test::suite if (withAmount) jv[field.fieldName] = USD(10).value().getJson(JsonOptions::none); if (field == sfAsset) + { jv[jss::Asset] = to_json(mpt.get()); + } else if (field == sfAsset2) + { jv[jss::Asset2] = to_json(mpt.get()); + } else + { jv[field.fieldName] = mpt.getJson(JsonOptions::none); + } }; // All transactions with sfAmount, which don't support MPT. // Transactions with amount fields, which can't be MPT. diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index 8cd67bd72b..25f5a0f880 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -96,14 +96,18 @@ class NFTokenBurn_test : public beast::unit_test::suite else { if (tokenCount > 0) + { std::cout << "first: " << state[i][sfNFTokens.jsonName][0u].toStyledString() << std::endl; + } if (tokenCount > 1) + { std::cout << "last: " << state[i][sfNFTokens.jsonName][tokenCount - 1].toStyledString() << std::endl; + } } } } @@ -256,7 +260,7 @@ class NFTokenBurn_test : public beast::unit_test::suite std::uniform_int_distribution acctDist(0, 2); std::uniform_int_distribution mintDist(0, 1); - while (stats[0]->nfts.size() > 0 || stats[1]->nfts.size() > 0 || stats[2]->nfts.size() > 0) + while (!stats[0]->nfts.empty() || !stats[1]->nfts.empty() || !stats[2]->nfts.empty()) { // Pick an account to burn an nft. If there are no nfts left // pick again. @@ -273,14 +277,20 @@ class NFTokenBurn_test : public beast::unit_test::suite // Decide which of the accounts should burn the nft. If the // owner is becky then any of the three accounts can burn. // Otherwise either alice or minter can burn. - AcctStat& burner = owner.acct == becky.acct ? *(stats[acctDist(engine)]) - : mintDist(engine) ? alice - : minter; + AcctStat& burner = [&]() -> AcctStat& { + if (owner.acct == becky.acct) + return *(stats[acctDist(engine)]); + return mintDist(engine) ? alice : minter; + }(); if (owner.acct == burner.acct) + { env(token::burn(burner, nft)); + } else + { env(token::burn(burner, nft), token::owner(owner)); + } env.close(); // Every time we burn an nft, the number of nfts they hold should diff --git a/src/test/app/NFTokenDir_test.cpp b/src/test/app/NFTokenDir_test.cpp index 551b987204..73698f1f89 100644 --- a/src/test/app/NFTokenDir_test.cpp +++ b/src/test/app/NFTokenDir_test.cpp @@ -57,14 +57,18 @@ class NFTokenDir_test : public beast::unit_test::suite else { if (tokenCount > 0) + { std::cout << "first: " << state[i][sfNFTokens.jsonName][0u].toStyledString() << std::endl; + } if (tokenCount > 1) + { std::cout << "last: " << state[i][sfNFTokens.jsonName][tokenCount - 1].toStyledString() << std::endl; + } } } } diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 95dfc60c41..d9010d5d6e 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -171,7 +171,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite int line) { auto oneCheck = [line, this](char const* type, std::uint32_t found, std::uint32_t exp) { if (found == exp) + { pass(); + } else { std::stringstream ss; @@ -269,7 +271,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto oneCheck = [this](char const* type, std::uint32_t found, std::uint32_t exp, int line) { if (found == exp) + { pass(); + } else { std::stringstream ss; @@ -2171,9 +2175,13 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite for (auto NumberSwitchOver : {true}) { if (NumberSwitchOver) + { env.enableFeature(fixUniversalNumber); + } else + { env.disableFeature(fixUniversalNumber); + } // An nft with a transfer fee of 1 basis point. uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1); @@ -2347,7 +2355,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto check = [this](std::uint32_t taxon, uint256 const& nftID) { nft::Taxon const gotTaxon = nft::getTaxon(nftID); if (nft::toTaxon(taxon) == gotTaxon) + { pass(); + } else { std::stringstream ss; @@ -4791,7 +4801,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXPB))); auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU); if (brokerDiff > gwXAU(0)) + { env(pay(gw, broker, brokerDiff)); + } else if (brokerDiff < gwXAU(0)) { brokerDiff.negate(); @@ -6976,7 +6988,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite auto checkURI = [&accountNFTs, this](Account const& acct, char const* uri, int line) { auto const nfts = accountNFTs(acct); if (nfts.size() == 1) + { pass(); + } else { std::ostringstream text; @@ -6988,7 +7002,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite if (uri == nullptr) { if (!nfts[0u].isMember(sfURI.jsonName)) + { pass(); + } else { std::ostringstream text; @@ -6999,7 +7015,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } if (nfts[0u][sfURI.jsonName] == strHex(std::string(uri))) + { pass(); + } else { std::ostringstream text; diff --git a/src/test/app/Offer_test.cpp b/src/test/app/Offer_test.cpp index bfda01f672..62edc844c7 100644 --- a/src/test/app/Offer_test.cpp +++ b/src/test/app/Offer_test.cpp @@ -1208,7 +1208,7 @@ public: { auto acctOffers = offersOnAccount(env, account_to_test); - BEAST_EXPECT(acctOffers.size() == 0); + BEAST_EXPECT(acctOffers.empty()); for (auto const& offerPtr : acctOffers) { auto const& offer = *offerPtr; @@ -1926,9 +1926,13 @@ public: { Env env{*this, features}; if (NumberSwitchOver) + { env.enableFeature(fixUniversalNumber); + } else + { env.disableFeature(fixUniversalNumber); + } auto const gw = Account{"gateway"}; auto const alice = Account{"alice"}; @@ -2281,7 +2285,7 @@ public: auto acctOffers = offersOnAccount(env, acct); BEAST_EXPECT(acctOffers.size() == t.offers); - if (acctOffers.size() && t.offers) + if (!acctOffers.empty() && t.offers) { auto const& acctOffer = *(acctOffers.front()); @@ -2592,7 +2596,7 @@ public: // In pre-flow code alice's offer is left empty in the ledger. auto const aliceOffers = offersOnAccount(env, alice); - if (aliceOffers.size() != 0) + if (!aliceOffers.empty()) { BEAST_EXPECT(aliceOffers.size() == 1); auto const& aliceOffer = *(aliceOffers.front()); @@ -2772,7 +2776,7 @@ public: if (t.offers) { auto const acctOffers = offersOnAccount(env, acct); - if (acctOffers.size() > 0) + if (!acctOffers.empty()) { BEAST_EXPECT(acctOffers.size() == 1); auto const& acctOffer = *(acctOffers.front()); @@ -2984,7 +2988,7 @@ public: env.require(balance(eve, XRP(18000))); auto const evesOffers = offersOnAccount(env, eve); BEAST_EXPECT(evesOffers.size() == 1); - if (evesOffers.size() != 0) + if (!evesOffers.empty()) { auto const& evesOffer = *(evesOffers.front()); BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER); @@ -3160,7 +3164,7 @@ public: // In pre-flow code ova's offer is left empty in the ledger. auto const ovasOffers = offersOnAccount(env, ova); - if (ovasOffers.size() != 0) + if (!ovasOffers.empty()) { BEAST_EXPECT(ovasOffers.size() == 1); auto const& ovasOffer = *(ovasOffers.front()); @@ -4593,8 +4597,10 @@ public: std::map> offers; forEachItem(*env.current(), alice, [&](std::shared_ptr const& sle) { if (sle->getType() == ltOFFER) + { offers.emplace( (*sle)[sfSequence], std::make_pair((*sle)[sfTakerPays], (*sle)[sfTakerGets])); + } }); // first offer @@ -4749,7 +4755,7 @@ public: // Verify that the third offer alice created was consumed. { auto offers = sortedOffersOnAccount(env, alice); - BEAST_EXPECT(offers.size() == 0); + BEAST_EXPECT(offers.empty()); } env.require(balance(alice, USD(0))); env.require(owners(alice, 1)); diff --git a/src/test/app/OversizeMeta_test.cpp b/src/test/app/OversizeMeta_test.cpp index d5e2948f5b..3831e45a78 100644 --- a/src/test/app/OversizeMeta_test.cpp +++ b/src/test/app/OversizeMeta_test.cpp @@ -123,7 +123,9 @@ public: len -= l2 + 1; } else + { len = l2; + } } return lo; } diff --git a/src/test/app/Path_test.cpp b/src/test/app/Path_test.cpp index 283abb330e..9315370809 100644 --- a/src/test/app/Path_test.cpp +++ b/src/test/app/Path_test.cpp @@ -1518,7 +1518,7 @@ public: } else { - BEAST_EXPECT(st.size() == 0); + BEAST_EXPECT(st.empty()); BEAST_EXPECT(equal(sa, XRP(0))); } }; diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index ba79eb037d..5322349797 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -1015,9 +1015,11 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(r[jss::result][jss::validated]); BEAST_EXPECT(chan1Str != chan2Str); for (auto const& c : {chan1Str, chan2Str}) + { BEAST_EXPECT( r[jss::result][jss::channels][0u][jss::channel_id] == c || r[jss::result][jss::channels][1u][jss::channel_id] == c); + } } } @@ -1249,9 +1251,11 @@ struct PayChan_test : public beast::unit_test::suite BEAST_EXPECT(r[jss::result][jss::validated]); BEAST_EXPECT(chan1Str != chan2Str); for (auto const& c : {chan1Str, chan2Str}) + { BEAST_EXPECT( r[jss::result][jss::channels][0u][jss::channel_id] == c || r[jss::result][jss::channels][1u][jss::channel_id] == c); + } } auto sliceToHex = [](Slice const& slice) { diff --git a/src/test/app/PayStrand_test.cpp b/src/test/app/PayStrand_test.cpp index 16e7a857ff..70444637bf 100644 --- a/src/test/app/PayStrand_test.cpp +++ b/src/test/app/PayStrand_test.cpp @@ -183,8 +183,10 @@ class ElementComboIter hasAny(std::initializer_list sb) const { for (auto const s : sb) + { if (has(s)) return true; + } return false; } @@ -194,8 +196,10 @@ class ElementComboIter size_t result = 0; for (auto const s : sb) + { if (has(s)) result++; + } return result; } @@ -275,13 +279,17 @@ public: return currencyF(); }(); if (!has(SB::boundary)) + { col.emplace_back(acc, cur, iss); + } else + { col.emplace_back( STPathElement::Type::typeBoundary, acc.value_or(AccountID{}), cur.value_or(Currency{}), iss.value_or(AccountID{})); + } } }; @@ -368,11 +376,17 @@ struct ExistingElementPool for (size_t id = 0; id < numCur; ++id) { if (id < 10) + { snprintf(buf, bufSize, "CC%zu", id); + } else if (id < 100) + { snprintf(buf, bufSize, "C%zu", id); + } else + { snprintf(buf, bufSize, "%zu", id); + } currencies.emplace_back(to_currency(buf)); currencyNames.emplace_back(buf); } @@ -407,8 +421,10 @@ struct ExistingElementPool std::vector ious; ious.reserve(numAct * numCur); for (auto const& a : accounts) + { for (auto const& cn : currencyNames) ious.emplace_back(a[cn]); + } // create offers from every currency to every other currency for (auto takerPays = ious.begin(), ie = ious.end(); takerPays != ie; ++takerPays) diff --git a/src/test/app/PermissionedDomains_test.cpp b/src/test/app/PermissionedDomains_test.cpp index d2a14ce82a..c4bbd80e74 100644 --- a/src/test/app/PermissionedDomains_test.cpp +++ b/src/test/app/PermissionedDomains_test.cpp @@ -199,9 +199,13 @@ class PermissionedDomains_test : public beast::unit_test::suite uint256 d; if (domain) + { d = *domain; + } else + { d = pdomain::getNewDomain(env.meta()); + } env.close(); auto objects = pdomain::getObjects(account, env); auto const fromObject = pdomain::credentialsFromJson(objects[d], human2Acc); @@ -228,9 +232,13 @@ class PermissionedDomains_test : public beast::unit_test::suite uint256 d; if (domain) + { d = *domain; + } else + { d = pdomain::getNewDomain(env.meta()); + } env.close(); auto objects = pdomain::getObjects(account, env); auto const fromObject = pdomain::credentialsFromJson(objects[d], human2Acc); @@ -479,7 +487,7 @@ class PermissionedDomains_test : public beast::unit_test::suite pdomain::Credentials credentials{{alice, "first credential"}}; env(pdomain::setTx(alice, credentials), ter(tecINSUFFICIENT_RESERVE)); BEAST_EXPECT(env.ownerCount(alice) == 0); - BEAST_EXPECT(pdomain::getObjects(alice, env).size() == 0); + BEAST_EXPECT(pdomain::getObjects(alice, env).empty()); env.close(); auto const baseFee = env.current()->fees().base.drops(); diff --git a/src/test/app/RCLValidations_test.cpp b/src/test/app/RCLValidations_test.cpp index 140ba9f1d7..a7941ea64f 100644 --- a/src/test/app/RCLValidations_test.cpp +++ b/src/test/app/RCLValidations_test.cpp @@ -112,9 +112,13 @@ class RCLValidations_test : public beast::unit_test::suite for (Seq s = a.seq(); s > 0; s--) { if (s >= a.minSeq()) + { BEAST_EXPECT(a[s] == history[s - 1]->header().hash); + } else + { BEAST_EXPECT(a[s] == ID{0}); + } } } diff --git a/src/test/app/ReducedOffer_test.cpp b/src/test/app/ReducedOffer_test.cpp index 737d73e462..d0cf1b5324 100644 --- a/src/test/app/ReducedOffer_test.cpp +++ b/src/test/app/ReducedOffer_test.cpp @@ -92,9 +92,11 @@ public: // alice's offer should be fully crossed and so gone from // the ledger. if (!BEAST_EXPECT(!offerInLedger(env, alice, aliceOfferSeq))) + { // If the in-ledger offer was not consumed then further // results are meaningless. return 1; + } // bob's offer should be in the ledger, but reduced in size. unsigned int badRate = 1; diff --git a/src/test/app/SHAMapStore_test.cpp b/src/test/app/SHAMapStore_test.cpp index 97a9a38e77..d7d3e281f4 100644 --- a/src/test/app/SHAMapStore_test.cpp +++ b/src/test/app/SHAMapStore_test.cpp @@ -190,7 +190,7 @@ public: ledgers.emplace(std::make_pair(i, env.rpc("ledger", std::to_string(i)))); BEAST_EXPECT( goodLedger(env, ledgers[i], std::to_string(i), true) && - getHash(ledgers[i]).length()); + !getHash(ledgers[i]).empty()); } ledgerCheck(env, deleteInterval + 1, 2); @@ -229,7 +229,7 @@ public: store.getLastRotated() == lastRotated || i == lastRotated + deleteInterval - 2); BEAST_EXPECT( goodLedger(env, ledgers[i], std::to_string(i), true) && - getHash(ledgers[i]).length()); + !getHash(ledgers[i]).empty()); } store.rendezvous(); diff --git a/src/test/app/SetTrust_test.cpp b/src/test/app/SetTrust_test.cpp index 06aebcd915..fdc73eed79 100644 --- a/src/test/app/SetTrust_test.cpp +++ b/src/test/app/SetTrust_test.cpp @@ -151,9 +151,13 @@ public: testFreeTrustlines(FeatureBitset features, bool thirdLineCreatesLE, bool createOnHighAcct) { if (thirdLineCreatesLE) + { testcase("Allow two free trustlines"); + } else + { testcase("Dynamic reserve for trustline"); + } using namespace jtx; Env env(*this, features); @@ -284,8 +288,10 @@ public: badFlag *= 2) { if (badFlag & tfTrustSetMask) + { env(trust(alice, gw["USD"](100), static_cast(badFlag)), ter(temINVALID_FLAG)); + } } // trust amount can't be XRP diff --git a/src/test/app/TheoreticalQuality_test.cpp b/src/test/app/TheoreticalQuality_test.cpp index e272f2aedb..b4f6f3697d 100644 --- a/src/test/app/TheoreticalQuality_test.cpp +++ b/src/test/app/TheoreticalQuality_test.cpp @@ -57,10 +57,15 @@ struct RippleCalcTestParams auto const currency = to_currency(pe[jss::currency].asString()); std::optional issuer; if (!isXRP(currency)) + { // NOLINTNEXTLINE(bugprone-unchecked-optional-access) issuer = *parseBase58(pe[jss::issuer].asString()); + } else + { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) assert(isXRP(*parseBase58(pe[jss::issuer].asString()))); + } p.emplace_back(std::nullopt, currency, issuer); } else @@ -148,7 +153,7 @@ public: jtx::Env& env, jtx::Account const& acc, jtx::Account const& peer, - Currency const& currency) + Currency const& currency) const { using namespace jtx; IOU const iou{acc, currency}; diff --git a/src/test/app/Ticket_test.cpp b/src/test/app/Ticket_test.cpp index 760cce88be..35fc7ea979 100644 --- a/src/test/app/Ticket_test.cpp +++ b/src/test/app/Ticket_test.cpp @@ -286,11 +286,15 @@ class Ticket_test : public beast::unit_test::suite BEAST_EXPECT(prevTicketCount > 0); if (prevTicketCount == 1) + { BEAST_EXPECT(!finalFields.isMember(sfTicketCount.jsonName)); + } else + { BEAST_EXPECT( finalFields.isMember(sfTicketCount.jsonName) && finalFields[sfTicketCount.jsonName].asUInt() == prevTicketCount - 1); + } } } else if (node.isMember(sfDeletedNode.jsonName)) diff --git a/src/test/app/TrustAndBalance_test.cpp b/src/test/app/TrustAndBalance_test.cpp index 413ef6dd78..3a2aa8e7c9 100644 --- a/src/test/app/TrustAndBalance_test.cpp +++ b/src/test/app/TrustAndBalance_test.cpp @@ -343,12 +343,16 @@ class TrustAndBalance_test : public beast::unit_test::suite // alice pays amazon via multiple paths if (with_rate) + { env(pay(alice, amazon, gw["USD"](150)), sendmax(alice["USD"](200)), test::jtx::path(bob), test::jtx::path(carol)); + } else + { env(pay(alice, amazon, gw["USD"](150)), test::jtx::path(bob), test::jtx::path(carol)); + } if (with_rate) { diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index d183330aaf..59db7e0d5d 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -2757,14 +2757,18 @@ public: for (int i = 0; i < 5; ++i) { if (i == 2) + { envs( noop(alice), fee(baseFee * 100), seq(none), json(jss::LastLedgerSequence, lastLedgerSeq), ter(terQUEUED))(submitParams); + } else + { envs(noop(alice), fee(baseFee * 100), seq(none), ter(terQUEUED))(submitParams); + } } checkMetrics(*this, env, 5, std::nullopt, 7, 6); { diff --git a/src/test/app/ValidatorList_test.cpp b/src/test/app/ValidatorList_test.cpp index 679fad800f..32e899ad95 100644 --- a/src/test/app/ValidatorList_test.cpp +++ b/src/test/app/ValidatorList_test.cpp @@ -1045,9 +1045,13 @@ private: auto const valKey = randomNode(); cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey)); if (cfgKeys.size() <= maxKeys - 5) + { activeValidatorsOuter.emplace(calcNodeID(valKey)); + } else + { unseenValidators.emplace(calcNodeID(valKey)); + } } BEAST_EXPECT(trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter)); @@ -1075,7 +1079,9 @@ private: BEAST_EXPECT(trustedKeysOuter->trusted(*valKey)); } else + { fail(); + } } changes = trustedKeysOuter->updateTrusted( @@ -1266,9 +1272,13 @@ private: cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey)); expectedTrusted.emplace(calcNodeID(valKey)); if (cfgKeys.size() < std::ceil(n * 0.8f)) + { activeValidators.emplace(calcNodeID(valKey)); + } else if (cfgKeys.size() < std::ceil(n * 0.8f)) + { toBeSeen = calcNodeID(valKey); + } } BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishersOuter)); @@ -1462,9 +1472,13 @@ private: env.app().getHashRouter()); BEAST_EXPECT(changes.removed.empty()); if (cfgKeys.size() > 2) + { BEAST_EXPECT(changes.added == asNodeIDs({valKey})); + } else + { BEAST_EXPECT(changes.added == asNodeIDs({localKey, valKey})); + } BEAST_EXPECT(trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f)); @@ -1617,14 +1631,28 @@ private: auto const sequence = 1; using namespace std::chrono_literals; // Want to drop 1 sooner - NetClock::time_point const validUntil = env.timeKeeper().now() + - (i == 2 ? 120s - : i == 1 ? 60s - : 3600s); + std::chrono::seconds duration; + if (i == 2) + { + duration = 120s; + } + else if (i == 1) + { + duration = 60s; + } + else + { + duration = 3600s; + } + NetClock::time_point const validUntil = env.timeKeeper().now() + duration; if (i == 1) + { validUntil1 = validUntil; + } else if (i == 2) + { validUntil2 = validUntil; + } std::vector localKeys{locals[i].first, locals[i].second}; auto const blob = makeList(localKeys, sequence, validUntil.time_since_epoch().count()); @@ -1665,7 +1693,9 @@ private: added.insert(calcNodeID(val.masterPublic)); } else + { BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic)); + } } BEAST_EXPECT(changes.added == added); BEAST_EXPECT(changes.removed.empty()); @@ -1689,7 +1719,9 @@ private: { auto const& val = valKeys[i]; if (i >= 2 && i < maxKeys - 4) + { BEAST_EXPECT(trustedKeys->trusted(val.masterPublic)); + } else { BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic)); @@ -1717,9 +1749,13 @@ private: { auto const& val = valKeys[i]; if (i < maxKeys - 4) + { BEAST_EXPECT(trustedKeys->listed(val.masterPublic)); + } else + { BEAST_EXPECT(!trustedKeys->listed(val.masterPublic)); + } BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic)); if (i >= 2 && i < maxKeys - 4) @@ -2020,7 +2056,7 @@ private: { for (auto& n : nUnl_temp) { - if (nUnl.find(n) == nUnl.end()) + if (!nUnl.contains(n)) return false; } validators->updateTrusted( @@ -2338,7 +2374,7 @@ private: 1, 8, maxSequence, version, manifest, blobInfos, messages), 0, 0); - BEAST_EXPECT(messages.size() == 0); + BEAST_EXPECT(messages.empty()); // Don't repeat the work if messages is populated, even though the // peerSequence provided indicates it should. Note that this @@ -2392,7 +2428,7 @@ private: 2, maxSequence * 2, maxSequence, version, manifest, blobInfos, messages), 0, 0); - BEAST_EXPECT(messages.size() == 0); + BEAST_EXPECT(messages.empty()); // Don't repeat the work if messages is populated, even though the // peerSequence provided indicates it should. Note that this @@ -2491,7 +2527,7 @@ private: PublicKey pubKey; std::pair signingKeys; std::string manifest; - NetClock::time_point expiry = {}; + NetClock::time_point expiry = {}; // NOLINT(readability-redundant-member-init) }; // Create ValidatorList with a set of countTotal publishers, of which @@ -2528,7 +2564,12 @@ private: pubSigningKeys.second, i < countRevoked ? revoked : 1)); publishers.push_back( - Publisher{i < countRevoked, publisherPublic, pubSigningKeys, manifest}); + Publisher{ + .revoked = i < countRevoked, + .pubKey = publisherPublic, + .signingKeys = pubSigningKeys, + .manifest = manifest, + }); } std::vector const emptyCfgKeys; @@ -2670,7 +2711,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().empty()); hash_set removed; for (auto const& val : valKeys) @@ -2938,7 +2979,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().empty()); hash_set removed; for (auto const& val : valKeys) @@ -3376,7 +3417,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().empty()); hash_set removed; for (auto const& val : valKeys) @@ -3558,7 +3599,7 @@ private: env.app().overlay(), env.app().getHashRouter()); BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled); - BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0); + BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().empty()); hash_set removed; for (auto const& val : valKeys) diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index eaae4c278e..c47c93c426 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -225,8 +225,10 @@ private: Json::Value myStatus; for (auto const& vs : jv[jss::validator_sites]) + { if (vs[jss::uri].asString().find(u.uri) != std::string::npos) myStatus = vs; + } BEAST_EXPECTS( myStatus[jss::last_refresh_message].asString().empty() != u.cfg.failFetch, to_string(myStatus) + "\n" + sink.messages().str()); @@ -307,8 +309,10 @@ private: auto const jv = sites->getJson(); Json::Value myStatus; for (auto const& vs : jv[jss::validator_sites]) + { if (vs[jss::uri].asString().find(u.uri) != std::string::npos) myStatus = vs; + } BEAST_EXPECTS( myStatus[jss::last_refresh_message].asString().empty() != u.shouldFail, to_string(myStatus)); diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index 5a5292b06c..e62f7fee50 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -66,15 +66,23 @@ class Vault_test : public beast::unit_test::suite auto const vault = env.le(keylet); BEAST_EXPECT(vault != nullptr); if (!asset.integral()) + { BEAST_EXPECT(vault->at(sfScale) == 6); + } else + { BEAST_EXPECT(vault->at(sfScale) == 0); + } auto const shares = env.le(keylet::mptIssuance(vault->at(sfShareMPTID))); BEAST_EXPECT(shares != nullptr); if (!asset.integral()) + { BEAST_EXPECT(shares->at(sfAssetScale) == 6); + } else + { BEAST_EXPECT(shares->at(sfAssetScale) == 0); + } return {MPTIssue(vault->at(sfShareMPTID)), Account("vault", vault->at(sfAccount))}; }(); auto const shares = share.raw().get(); @@ -1330,11 +1338,17 @@ class Vault_test : public beast::unit_test::suite BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); if (!asset1.native() && !asset2.native()) + { fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All); + } else if (asset1.native()) + { fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All); + } else if (asset2.native()) + { fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All); + } AMM ammAlice(env, alice, asset1, asset2, CreateArg{.log = false, .tfee = 0}); @@ -2276,7 +2290,9 @@ class Vault_test : public beast::unit_test::suite env(fset(issuer, asfDefaultRipple)); } else + { env.trust(asset(1000), charlie); + } env.close(); env(rate(issuer, args.transferRate)); env.close(); @@ -4605,18 +4621,23 @@ class Vault_test : public beast::unit_test::suite { testcase("VaultClawback (share) - " + prefix + " owner asset clawback fails"); auto [vault, vaultKeylet] = setupVault(asset, owner, depositor); + // when asset is XRP or owner is not issuer clawback fail + // when owner is issuer precision loss occurs as vault is + // empty + auto const expectedTer = [&]() { + if (asset.native()) + return ter(temMALFORMED); + if (asset.raw().getIssuer() != owner.id()) + return ter(tecNO_PERMISSION); + return ter(tecPRECISION_LOSS); + }(); env(vault.clawback({ .issuer = owner, .id = vaultKeylet.key, .holder = depositor, .amount = asset(100).value(), }), - // when asset is XRP or owner is not issuer clawback fail - // when owner is issuer precision loss occurs as vault is - // empty - asset.native() ? ter(temMALFORMED) - : asset.raw().getIssuer() != owner.id() ? ter(tecNO_PERMISSION) - : ter(tecPRECISION_LOSS)); + expectedTer); env.close(); } diff --git a/src/test/app/XChain_test.cpp b/src/test/app/XChain_test.cpp index 2265d9f33b..b90ff49a84 100644 --- a/src/test/app/XChain_test.cpp +++ b/src/test/app/XChain_test.cpp @@ -2142,14 +2142,22 @@ struct XChain_test : public beast::unit_test::suite, public jtx::XChainBridgeObj TER const expectedTER = i < quorum ? tesSUCCESS : TER{tecXCHAIN_NO_CLAIM_ID}; if (i + 1 == quorum) + { scEnv.tx(att, ter(expectedTER)).close(); + } else + { scEnv.tx(att, ter(expectedTER)).close(); + } if (i + 1 < quorum) + { BEAST_EXPECT(dstStartBalance == scEnv.env_.balance(dst)); + } else + { BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst)); + } } BEAST_EXPECT(dstStartBalance + amt == scEnv.env_.balance(dst)); } @@ -2336,9 +2344,13 @@ struct XChain_test : public beast::unit_test::suite, public jtx::XChainBridgeObj scEnv.tx(att, ter(expectedTER)).close(); if (i + 1 < xrp_b.quorum) + { BEAST_EXPECT(!scEnv.env_.le(ua)); + } else + { BEAST_EXPECT(scEnv.env_.le(ua)); + } } BEAST_EXPECT(scEnv.env_.le(ua)); } @@ -3917,8 +3929,10 @@ private: verify() const { for (auto const& [acct, state] : accounts) + { if (!state.verify(env, acct)) return false; + } return true; } @@ -4297,9 +4311,14 @@ private: break; case st_attesting: - sm_state = attest(time, rnd) - ? (xfer.with_claim == WithClaim::yes ? st_attested : st_completed) - : st_attesting; + if (attest(time, rnd)) + { + sm_state = xfer.with_claim == WithClaim::yes ? st_attested : st_completed; + } + else + { + sm_state = st_attesting; + } break; case st_attested: @@ -4366,9 +4385,13 @@ public: }; auto& [t, sm] = *it; if (t <= time && std::visit(vis, sm) == st_completed) + { it = sm_.erase(it); + } else + { ++it; + } } // send attestations @@ -4408,8 +4431,10 @@ public: std::vector result; result.reserve(num_acct); for (int i = 0; i < num_acct; ++i) + { result.emplace_back( "a"s + std::to_string(i), (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); + } result.emplace_back("doorXRPLocking"); doorXRPLocking = result.back(); result.emplace_back("doorUSDLocking"); @@ -4458,8 +4483,10 @@ public: std::vector result; result.reserve(num_ua); for (int i = 0; i < num_ua; ++i) + { result.emplace_back( "ua"s + std::to_string(i), (i % 2) ? KeyType::ed25519 : KeyType::secp256k1); + } return result; }(); diff --git a/src/test/basics/Buffer_test.cpp b/src/test/basics/Buffer_test.cpp index 675228c42f..f5f626133f 100644 --- a/src/test/basics/Buffer_test.cpp +++ b/src/test/basics/Buffer_test.cpp @@ -12,7 +12,7 @@ struct Buffer_test : beast::unit_test::suite bool sane(Buffer const& b) const { - if (b.size() == 0) + if (b.empty()) return b.data() == nullptr; return b.data() != nullptr; @@ -241,13 +241,13 @@ struct Buffer_test : beast::unit_test::suite // Try to clear: x.clear(); BEAST_EXPECT(sane(x)); - BEAST_EXPECT(x.size() == 0); + BEAST_EXPECT(x.empty()); BEAST_EXPECT(x.data() == nullptr); // Try to clear again: x.clear(); BEAST_EXPECT(sane(x)); - BEAST_EXPECT(x.size() == 0); + BEAST_EXPECT(x.empty()); BEAST_EXPECT(x.data() == nullptr); }; diff --git a/src/test/basics/IntrusiveShared_test.cpp b/src/test/basics/IntrusiveShared_test.cpp index 817cbb8c1d..5a460a6044 100644 --- a/src/test/basics/IntrusiveShared_test.cpp +++ b/src/test/basics/IntrusiveShared_test.cpp @@ -144,7 +144,7 @@ public: } void - partialDestructor() + partialDestructor() const { using enum TrackedState; @@ -245,7 +245,7 @@ public: while (!weak.empty()) { weak.resize(weak.size() - 1); - if (weak.size()) + if (!weak.empty()) BEAST_EXPECT(TIBase::getState(id) == partiallyDeleted); } BEAST_EXPECT(TIBase::getState(id) == deleted); diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index eaf184ffe4..fb434a0182 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -199,9 +199,13 @@ public: } }; if (scale == MantissaRange::small) + { test(cSmall); + } else + { test(cLarge); + } { bool caught = false; try @@ -291,9 +295,13 @@ public: } }; if (scale == MantissaRange::small) + { test(cSmall); + } else + { test(cLarge); + } } void @@ -314,9 +322,13 @@ public: }; auto tests = [&](auto const& cSmall, auto const& cLarge) { if (scale == MantissaRange::small) + { test(cSmall); + } else + { test(cLarge); + } }; auto const maxMantissa = Number::maxMantissa(); @@ -622,9 +634,13 @@ public: auto const maxMantissa = Number::maxMantissa(); auto tests = [&](auto const& cSmall, auto const& cLarge) { if (scale == MantissaRange::small) + { test(cSmall); + } else + { test(cLarge); + } }; saveNumberRoundMode save{Number::setround(Number::to_nearest)}; { diff --git a/src/test/basics/PerfLog_test.cpp b/src/test/basics/PerfLog_test.cpp index 6e73b5f696..ce0109c53d 100644 --- a/src/test/basics/PerfLog_test.cpp +++ b/src/test/basics/PerfLog_test.cpp @@ -87,7 +87,10 @@ class PerfLog_test : public beast::unit_test::suite { perf::PerfLog::Setup const setup{ withFile == WithFile::no ? "" : logFile(), logInterval()}; - return perf::make_PerfLog(setup, app_, j_, [this]() { return signalStop(); }); + return perf::make_PerfLog(setup, app_, j_, [this]() { + signalStop(); + return; + }); } // Block until the log file has grown in size, indicating that the @@ -451,8 +454,10 @@ public: Json::Value parsedLastLine; Json::Reader().parse(lastLine, parsedLastLine); if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine))) + { // Avoid cascade of failures return; + } // Validate the contents of the last line of the log. validateFinalCounters(parsedLastLine[jss::counters]); @@ -770,8 +775,10 @@ public: Json::Value parsedLastLine; Json::Reader().parse(lastLine, parsedLastLine); if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine))) + { // Avoid cascade of failures return; + } // Validate the contents of the last line of the log. validateFinalCounters(parsedLastLine[jss::counters]); @@ -908,8 +915,10 @@ public: Json::Value parsedLastLine; Json::Reader().parse(lastLine, parsedLastLine); if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine))) + { // Avoid cascade of failures return; + } // Validate the contents of the last line of the log. verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36); diff --git a/src/test/basics/XRPAmount_test.cpp b/src/test/basics/XRPAmount_test.cpp index 8b8d657123..58b15b5d2d 100644 --- a/src/test/basics/XRPAmount_test.cpp +++ b/src/test/basics/XRPAmount_test.cpp @@ -16,11 +16,17 @@ public: XRPAmount const x(i); if (i < 0) + { BEAST_EXPECT(x.signum() < 0); + } else if (i > 0) + { BEAST_EXPECT(x.signum() > 0); + } else + { BEAST_EXPECT(x.signum() == 0); + } } } diff --git a/src/test/beast/LexicalCast_test.cpp b/src/test/beast/LexicalCast_test.cpp index 0c84e075c6..5cfc73a6f6 100644 --- a/src/test/beast/LexicalCast_test.cpp +++ b/src/test/beast/LexicalCast_test.cpp @@ -220,7 +220,7 @@ public: testcase("entire range"); std::int32_t i = std::numeric_limits::min(); - std::string const empty(""); + std::string const empty; while (i <= std::numeric_limits::max()) { diff --git a/src/test/conditions/PreimageSha256_test.cpp b/src/test/conditions/PreimageSha256_test.cpp index 5c9ec5e552..973f714ba4 100644 --- a/src/test/conditions/PreimageSha256_test.cpp +++ b/src/test/conditions/PreimageSha256_test.cpp @@ -17,7 +17,7 @@ namespace cryptoconditions { class PreimageSha256_test : public beast::unit_test::suite { - inline Buffer + Buffer hexblob(std::string const& s) { auto blob = strUnHex(s); diff --git a/src/test/consensus/Consensus_test.cpp b/src/test/consensus/Consensus_test.cpp index 0d023f270d..a096b82365 100644 --- a/src/test/consensus/Consensus_test.cpp +++ b/src/test/consensus/Consensus_test.cpp @@ -157,7 +157,7 @@ public: BEAST_EXPECT(peer->prevLedgerID() == lcl.id()); BEAST_EXPECT(lcl.seq() == Ledger::Seq{1}); BEAST_EXPECT(lcl.txs().size() == 1); - BEAST_EXPECT(lcl.txs().find(Tx{1}) != lcl.txs().end()); + BEAST_EXPECT(lcl.txs().contains(Tx{1})); BEAST_EXPECT(peer->prevProposers == 0); } @@ -193,7 +193,7 @@ public: BEAST_EXPECT(peer->prevProposers == peers.size() - 1); // All transactions were accepted for (std::uint32_t i = 0; i < peers.size(); ++i) - BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end()); + BEAST_EXPECT(lcl.txs().contains(Tx{i})); } } } @@ -244,12 +244,12 @@ public: BEAST_EXPECT(peer->prevProposers == network.size() - 1); BEAST_EXPECT(peer->prevRoundTime == network[0]->prevRoundTime); - BEAST_EXPECT(lcl.txs().find(Tx{0}) == lcl.txs().end()); + BEAST_EXPECT(not lcl.txs().contains(Tx{0})); for (std::uint32_t i = 2; i < network.size(); ++i) - BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end()); + BEAST_EXPECT(lcl.txs().contains(Tx{i})); // Tx 0 didn't make it - BEAST_EXPECT(peer->openTxs.find(Tx{0}) != peer->openTxs.end()); + BEAST_EXPECT(peer->openTxs.contains(Tx{0})); } } } @@ -297,21 +297,25 @@ public: // Closed ledger has all but transaction 0,1 auto const& lcl = peer->lastClosedLedger; BEAST_EXPECT(lcl.seq() == Ledger::Seq{1}); - BEAST_EXPECT(lcl.txs().find(Tx{0}) == lcl.txs().end()); - BEAST_EXPECT(lcl.txs().find(Tx{1}) == lcl.txs().end()); + BEAST_EXPECT(not lcl.txs().contains(Tx{0})); + BEAST_EXPECT(not lcl.txs().contains(Tx{1})); for (std::uint32_t i = slow.size(); i < network.size(); ++i) - BEAST_EXPECT(lcl.txs().find(Tx{i}) != lcl.txs().end()); + BEAST_EXPECT(lcl.txs().contains(Tx{i})); // Tx 0-1 didn't make it - BEAST_EXPECT(peer->openTxs.find(Tx{0}) != peer->openTxs.end()); - BEAST_EXPECT(peer->openTxs.find(Tx{1}) != peer->openTxs.end()); + BEAST_EXPECT(peer->openTxs.contains(Tx{0})); + BEAST_EXPECT(peer->openTxs.contains(Tx{1})); } Peer const* slowPeer = slow[0]; if (isParticipant) + { BEAST_EXPECT(slowPeer->prevProposers == network.size() - 1); + } else + { BEAST_EXPECT(slowPeer->prevProposers == fast.size()); + } for (Peer* peer : fast) { @@ -726,7 +730,9 @@ public: // Since the overlapped nodes have a UNL that is the union of the // two cliques, the maximum sized UNL list is the number of peers if (overlap > 0.4 * numPeers) + { BEAST_EXPECT(sim.synchronized()); + } else { // Even if we do fork, there shouldn't be more than 3 ledgers @@ -1100,7 +1106,7 @@ public: BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT(clog->str() == ""); + BEAST_EXPECT(clog->str().empty()); // I'm in the majority, my vote should not change BEAST_EXPECT(!proposingTrue.updateVote(5, true, p)); @@ -1118,7 +1124,7 @@ public: BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT(clog->str() == ""); + BEAST_EXPECT(clog->str().empty()); // Right now, the vote is 51%. The requirement is about to jump to // 65% @@ -1212,7 +1218,7 @@ public: BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT(clog->str() == ""); + BEAST_EXPECT(clog->str().empty()); // Threshold jumps to 95% BEAST_EXPECT(proposingTrue.updateVote(220, true, p)); @@ -1253,7 +1259,7 @@ public: BEAST_EXPECT(!proposingFalse.stalled(p, true, peersUnchanged, j, clog)); BEAST_EXPECT(!followingTrue.stalled(p, false, peersUnchanged, j, clog)); BEAST_EXPECT(!followingFalse.stalled(p, false, peersUnchanged, j, clog)); - BEAST_EXPECT(clog->str() == ""); + BEAST_EXPECT(clog->str().empty()); } auto expectStalled = [this, &clog]( @@ -1301,7 +1307,7 @@ public: // true vote has changed recently, so not stalled BEAST_EXPECT(!proposingTrue.stalled(p, true, 0, j, clog)); - BEAST_EXPECT(clog->str() == ""); + BEAST_EXPECT(clog->str().empty()); // remaining votes have been unchanged in so long that we only // need to hit the second round at 95% to be stalled, regardless // of peers @@ -1314,7 +1320,7 @@ public: // true vote has changed recently, so not stalled BEAST_EXPECT(!proposingTrue.stalled(p, true, peersUnchanged, j, clog)); - BEAST_EXPECTS(clog->str() == "", clog->str()); + BEAST_EXPECTS(clog->str().empty(), clog->str()); // remaining votes have been unchanged in so long that we only // need to hit the second round at 95% to be stalled, regardless // of peers @@ -1340,7 +1346,7 @@ public: // true vote changed 2 rounds ago, and peers are changing, so // not stalled BEAST_EXPECT(!proposingTrue.stalled(p, true, 0, j, clog)); - BEAST_EXPECTS(clog->str() == "", clog->str()); + BEAST_EXPECTS(clog->str().empty(), clog->str()); // still stalled BEAST_EXPECT(proposingFalse.stalled(p, true, 0, j, clog)); expectStalled(98, false, 11 + i, 0, 2, __LINE__); diff --git a/src/test/consensus/LedgerTiming_test.cpp b/src/test/consensus/LedgerTiming_test.cpp index 62902d6a28..945f6b4ff0 100644 --- a/src/test/consensus/LedgerTiming_test.cpp +++ b/src/test/consensus/LedgerTiming_test.cpp @@ -29,11 +29,17 @@ class LedgerTiming_test : public beast::unit_test::suite nextCloseResolution = getNextLedgerTimeResolution(closeResolution, previousAgree, ++round); if (nextCloseResolution < closeResolution) + { ++res.decrease; + } else if (nextCloseResolution > closeResolution) + { ++res.increase; + } else + { ++res.equal; + } std::swap(nextCloseResolution, closeResolution); } while (round < rounds); return res; diff --git a/src/test/consensus/LedgerTrie_test.cpp b/src/test/consensus/LedgerTrie_test.cpp index 175a8d7616..7fd8c71b64 100644 --- a/src/test/consensus/LedgerTrie_test.cpp +++ b/src/test/consensus/LedgerTrie_test.cpp @@ -669,7 +669,7 @@ class LedgerTrie_test : public beast::unit_test::suite for (std::uint32_t i = 0; i < iterations; ++i) { // pick a random ledger history - std::string curr = ""; + std::string curr; char depth = depthDist(gen); char offset = 0; for (char d = 0; d < depth; ++d) @@ -681,9 +681,13 @@ class LedgerTrie_test : public beast::unit_test::suite // 50-50 to add remove if (flip(gen) == 0) + { t.insert(h[curr]); + } else + { t.remove(h[curr]); + } if (!BEAST_EXPECT(t.checkInvariants())) return; } diff --git a/src/test/consensus/NegativeUNL_test.cpp b/src/test/consensus/NegativeUNL_test.cpp index b71fb77796..23f7610300 100644 --- a/src/test/consensus/NegativeUNL_test.cpp +++ b/src/test/consensus/NegativeUNL_test.cpp @@ -835,9 +835,13 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite for (auto const& [n, score] : *scoreTable) { if (n == myId) + { BEAST_EXPECT(score == 256); + } else + { BEAST_EXPECT(score == 0); + } } } @@ -1306,11 +1310,17 @@ class NegativeUNLVoteScoreTable_test : public beast::unit_test::suite [&](std::shared_ptr const& l, std::size_t idx) -> bool { std::size_t k = 0; if (idx < 2) + { k = 0; + } else if (idx < 4) + { k = 1; + } else + { k = 2; + } bool add_50 = scorePattern[sp][k] == 50 && l->seq() % 2 == 0; bool add_100 = scorePattern[sp][k] == 100; @@ -1333,9 +1343,11 @@ class NegativeUNLVoteScoreTable_test : public beast::unit_test::suite if (scorePattern[sp][k] == 50) return score == 256 / 2; if (scorePattern[sp][k] == 100) + { return score == 256; - else - return false; + } + + return false; }; for (; i < 2; ++i) { @@ -1753,9 +1765,11 @@ applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass) { auto const res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal); if (pass) + { return isTesSuccess(res.ter); - else - return res.ter == tefFAILURE || res.ter == temDISABLED; + } + + return res.ter == tefFAILURE || res.ter == temDISABLED; } bool @@ -1791,7 +1805,7 @@ VerifyPubKeyAndSeq( return false; nUnlLedgerSeq.erase(it); } - return nUnlLedgerSeq.size() == 0; + return nUnlLedgerSeq.empty(); } std::size_t diff --git a/src/test/consensus/Validations_test.cpp b/src/test/consensus/Validations_test.cpp index e3c9901398..cf4498bd52 100644 --- a/src/test/consensus/Validations_test.cpp +++ b/src/test/consensus/Validations_test.cpp @@ -942,9 +942,13 @@ class Validations_test : public beast::unit_test::suite BEAST_EXPECT( vals.getNodesAfter(this->genesisLedger, genesisLedger.id()) == trustedVals.size()); if (trustedVals.empty()) + { BEAST_EXPECT(vals.getPreferred(this->genesisLedger) == std::nullopt); + } else + { BEAST_EXPECT(vals.getPreferred(this->genesisLedger)->second == testID); + } BEAST_EXPECT(vals.getTrustedForLedger(testID, testSeq) == trustedVals); BEAST_EXPECT(vals.numTrustedForLedger(testID) == trustedVals.size()); }; diff --git a/src/test/core/ClosureCounter_test.cpp b/src/test/core/ClosureCounter_test.cpp index fc56d7f6c9..fe3f0a219f 100644 --- a/src/test/core/ClosureCounter_test.cpp +++ b/src/test/core/ClosureCounter_test.cpp @@ -221,7 +221,7 @@ class ClosureCounter_test : public beast::unit_test::suite BEAST_EXPECT(result.copies == 0); BEAST_EXPECT(result.moves == 1); BEAST_EXPECT(result.str == "rvalue abcdefghijklmnopqrstuvwxyz!"); - BEAST_EXPECT(strRValue.str.size() == 0); // NOLINT(bugprone-use-after-move) + BEAST_EXPECT(strRValue.str.empty()); // NOLINT(bugprone-use-after-move) } } diff --git a/src/test/core/Config_test.cpp b/src/test/core/Config_test.cpp index c71406cc07..e9f7354482 100644 --- a/src/test/core/Config_test.cpp +++ b/src/test/core/Config_test.cpp @@ -284,7 +284,7 @@ port_wss_admin expectException([&c] { c.legacy("server"); }); // not a single line // set a legacy value - BEAST_EXPECT(c.legacy("not_in_file") == ""); + BEAST_EXPECT(c.legacy("not_in_file").empty()); c.legacy("not_in_file", "new_value"); BEAST_EXPECT(c.legacy("not_in_file") == "new_value"); } @@ -434,7 +434,7 @@ port_wss_admin // load will not. Config c; c.loadFromString(""); - BEAST_EXPECT(c.legacy("database_path") == ""); + BEAST_EXPECT(c.legacy("database_path").empty()); } } { @@ -533,7 +533,7 @@ main error = e.what(); } - BEAST_EXPECT(error == ""); + BEAST_EXPECT(error.empty()); BEAST_EXPECT(c.NETWORK_ID == 0); try @@ -546,7 +546,7 @@ main error = e.what(); } - BEAST_EXPECT(error == ""); + BEAST_EXPECT(error.empty()); BEAST_EXPECT(c.NETWORK_ID == 0); try @@ -561,7 +561,7 @@ main error = e.what(); } - BEAST_EXPECT(error == ""); + BEAST_EXPECT(error.empty()); BEAST_EXPECT(c.NETWORK_ID == 255); try @@ -576,7 +576,7 @@ main error = e.what(); } - BEAST_EXPECT(error == ""); + BEAST_EXPECT(error.empty()); BEAST_EXPECT(c.NETWORK_ID == 10000); } @@ -1337,7 +1337,7 @@ r.ripple.com:51235 auto val_3 = get(s, "a_string"); BEAST_EXPECT(val_3 == "mystring"); auto val_4 = get(s, "not_a_key"); - BEAST_EXPECT(val_4 == ""); + BEAST_EXPECT(val_4.empty()); auto val_5 = get(s, "not_a_key", "default"); BEAST_EXPECT(val_5 == "default"); @@ -1429,7 +1429,7 @@ r.ripple.com:51235 {"months", 2592000, 1, false}, {"years", 31536000, 1, false}}; - std::string space = ""; + std::string space; for (auto& [unit, sec, val, shouldPass] : units) { Config c; @@ -1437,22 +1437,30 @@ r.ripple.com:51235 [amendment_majority_time] )xrpldConfig"); toLoad += std::to_string(val) + space + unit; - space = space == "" ? " " : ""; + space = space.empty() ? " " : ""; try { c.loadFromString(toLoad); if (shouldPass) + { BEAST_EXPECT(c.AMENDMENT_MAJORITY_TIME.count() == val * sec); + } else + { fail(); + } } catch (std::runtime_error&) { if (!shouldPass) + { pass(); + } else + { fail(); + } } } } diff --git a/src/test/csf/BasicNetwork_test.cpp b/src/test/csf/BasicNetwork_test.cpp index eaef805f33..eee16c2ce1 100644 --- a/src/test/csf/BasicNetwork_test.cpp +++ b/src/test/csf/BasicNetwork_test.cpp @@ -33,8 +33,10 @@ public: if (id == 0) { for (auto const link : net.links(this)) + { net.send( this, link.target, [&, to = link.target] { to->receive(net, this, 1); }); + } } else { @@ -51,9 +53,11 @@ public: if (m < 5) { for (auto const link : net.links(this)) + { net.send(this, link.target, [&, mm = m, to = link.target] { to->receive(net, this, mm); }); + } } } }; diff --git a/src/test/csf/impl/ledgers.cpp b/src/test/csf/impl/ledgers.cpp index 12d461a214..33e9b123c5 100644 --- a/src/test/csf/impl/ledgers.cpp +++ b/src/test/csf/impl/ledgers.cpp @@ -58,7 +58,9 @@ mismatch(Ledger const& a, Ledger const& b) count -= step + Seq{1}; } else + { count = step; + } } return start; } @@ -88,9 +90,13 @@ LedgerOracle::accept( next.closeTimeResolution = closeTimeResolution; next.closeTimeAgree = consensusCloseTime != NetClock::time_point{}; if (next.closeTimeAgree) + { next.closeTime = effCloseTime(consensusCloseTime, closeTimeResolution, parent.closeTime()); + } else + { next.closeTime = parent.closeTime() + 1s; + } next.parentCloseTime = parent.closeTime(); next.parentID = parent.id(); diff --git a/src/test/jtx/Env_test.cpp b/src/test/jtx/Env_test.cpp index bd1867adb3..bd40ac9a81 100644 --- a/src/test/jtx/Env_test.cpp +++ b/src/test/jtx/Env_test.cpp @@ -707,8 +707,10 @@ public: auto const neverSupportedFeat = [&]() -> std::optional { auto const n = supported.size(); for (size_t i = 0; i < n; ++i) + { if (!supported[i]) return bitsetIndexToFeature(i); + } return std::nullopt; }(); @@ -721,7 +723,7 @@ public: } auto hasFeature = [](Env& env, uint256 const& f) { - return (env.app().config().features.find(f) != env.app().config().features.end()); + return (env.app().config().features.contains(f)); }; { diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index e1f6137a10..6b2042efda 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -53,8 +53,6 @@ AMM::AMM( , log_(log) , doClose_(close) , lastPurchasePrice_(0) - , bidMin_() - , bidMax_() , msig_(ms) , fee_(fee) , ammAccount_(create(tfee, flags, seq, ter)) @@ -123,9 +121,13 @@ AMM::create( if (flags) jv[jss::Flags] = *flags; if (fee_ != 0) + { jv[sfFee] = std::to_string(fee_); + } else + { jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops()); + } submit(jv, seq, ter); if (!ter || env_.ter() == tesSUCCESS) @@ -218,6 +220,7 @@ IOUAmount AMM::getLPTokensBalance(std::optional const& account) const { if (account) + { return accountHolds( *env_.current(), *account, @@ -225,6 +228,7 @@ AMM::getLPTokensBalance(std::optional const& account) const FreezeHandling::fhZERO_IF_FROZEN, env_.journal) .iou(); + } if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()))) return amm->getFieldAmount(sfLPTokenBalance).iou(); return IOUAmount{0}; @@ -442,15 +446,25 @@ AMM::deposit( if (!(jvFlags & tfDepositSubTx)) { if (tokens && !asset1In) + { jvFlags |= tfLPToken; + } else if (tokens && asset1In) + { jvFlags |= tfOneAssetLPToken; + } else if (asset1In && asset2In) + { jvFlags |= tfTwoAsset; + } else if (maxEP && asset1In) + { jvFlags |= tfLimitLPToken; + } else if (asset1In) + { jvFlags |= tfSingleAsset; + } } jv[jss::Flags] = jvFlags; return deposit(account, jv, assets, seq, ter); @@ -562,15 +576,25 @@ AMM::withdraw( if (!(jvFlags & tfWithdrawSubTx)) { if (tokens && !asset1Out) + { jvFlags |= tfLPToken; + } else if (asset1Out && asset2Out) + { jvFlags |= tfTwoAsset; + } else if (tokens && asset1Out) + { jvFlags |= tfOneAssetLPToken; + } else if (asset1Out && maxEP) + { jvFlags |= tfLimitLPToken; + } else if (asset1Out) + { jvFlags |= tfSingleAsset; + } } jv[jss::Flags] = jvFlags; return withdraw(account, jv, seq, assets, ter); @@ -615,7 +639,7 @@ AMM::vote( void AMM::vote(VoteArg const& arg) { - return vote(arg.account, arg.tfee, arg.flags, arg.seq, arg.assets, arg.err); + vote(arg.account, arg.tfee, arg.flags, arg.seq, arg.assets, arg.err); } Json::Value @@ -641,11 +665,15 @@ AMM::bid(BidArg const& arg) setTokens(jv, arg.assets); auto getBid = [&](auto const& bid) { if (std::holds_alternative(bid)) + { return STAmount{lptIssue_, std::get(bid)}; - else if (std::holds_alternative(bid)) + } + if (std::holds_alternative(bid)) + { return toSTAmount(std::get(bid), lptIssue_); - else - return std::get(bid); + } + + return std::get(bid); }; if (arg.bidMin) { @@ -659,7 +687,7 @@ AMM::bid(BidArg const& arg) saTokens.setJson(jv[jss::BidMax]); bidMax_ = saTokens.iou(); } - if (arg.authAccounts.size() > 0) + if (!arg.authAccounts.empty()) { Json::Value accounts(Json::arrayValue); for (auto const& account : arg.authAccounts) @@ -691,22 +719,38 @@ AMM::submit( if (msig_) { if (seq && ter) + { env_(jv, *msig_, *seq, *ter); + } else if (seq) + { env_(jv, *msig_, *seq); + } else if (ter) + { env_(jv, *msig_, *ter); + } else + { env_(jv, *msig_); + } } else if (seq && ter) + { env_(jv, *seq, *ter); + } else if (seq) + { env_(jv, *seq); + } else if (ter) + { env_(jv, *ter); + } else + { env_(jv); + } if (doClose_) env_.close(); } diff --git a/src/test/jtx/impl/AMMTest.cpp b/src/test/jtx/impl/AMMTest.cpp index eb39408fbd..ab8c1578a3 100644 --- a/src/test/jtx/impl/AMMTest.cpp +++ b/src/test/jtx/impl/AMMTest.cpp @@ -129,11 +129,17 @@ AMMTestBase::testAMM(std::function const& cb, TestAM BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); if (!asset1.native() && !asset2.native()) + { fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All); + } else if (asset1.native()) + { fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All); + } else if (asset2.native()) + { fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All); + } AMM ammAlice( env, alice, asset1, asset2, CreateArg{.log = false, .tfee = arg.tfee, .err = arg.ter}); diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index 35531634f4..3217f67cbe 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -107,7 +107,9 @@ Env::close(NetClock::time_point closeTime, std::optionalgetFieldU64(sfOutstandingAmount), 0, true}; return {amount, lookup(issuer).name()}; } - else - { - // Holder balance - auto const sle = le(keylet::mptoken(id, account)); - if (!sle) - return {STAmount(mptIssue, 0), account.name()}; - STAmount const amount{mptIssue, sle->getFieldU64(sfMPTAmount)}; - return {amount, lookup(issuer).name()}; - } + // Holder balance + auto const sle = le(keylet::mptoken(id, account)); + if (!sle) + return {STAmount(mptIssue, 0), account.name()}; + + STAmount const amount{mptIssue, sle->getFieldU64(sfMPTAmount)}; + return {amount, lookup(issuer).name()}; } PrettyAmount @@ -336,10 +342,14 @@ Env::parseResult(Json::Value const& jr) parsed.rpcCode.emplace(rpcSUCCESS); } else + { error(parsed, result); + } } else + { error(parsed, jr); + } return parsed; } @@ -362,16 +372,14 @@ Env::submit(JTx const& jt, std::source_location const& loc) return jr; } - else - { - // Parsing failed or the JTx is - // otherwise missing the stx field. - parsedResult.ter = ter_ = temMALFORMED; - return Json::Value(); - } + // Parsing failed or the JTx is + // otherwise missing the stx field. + parsedResult.ter = ter_ = temMALFORMED; + + return Json::Value(); }(); - return postconditions(jt, parsedResult, jr, loc); + postconditions(jt, parsedResult, jr, loc); } void @@ -409,7 +417,7 @@ Env::sign_and_submit(JTx const& jt, Json::Value params, std::source_location con test.expect(parsedResult.ter, "ter uninitialized!"); ter_ = parsedResult.ter.value_or(telENV_RPC_FAILED); - return postconditions(jt, parsedResult, jr, loc); + postconditions(jt, parsedResult, jr, loc); } void @@ -532,9 +540,13 @@ Env::autofill_sig(JTx& jt) } auto const ar = le(account); if (ar && ar->isFieldPresent(sfRegularKey)) + { jtx::sign(jv, lookup(ar->getAccountID(sfRegularKey))); + } else + { jtx::sign(jv, account); + } } void diff --git a/src/test/jtx/impl/JSONRPCClient.cpp b/src/test/jtx/impl/JSONRPCClient.cpp index b635050984..6b60744aad 100644 --- a/src/test/jtx/impl/JSONRPCClient.cpp +++ b/src/test/jtx/impl/JSONRPCClient.cpp @@ -35,8 +35,10 @@ class JSONRPCClient : public AbstractClient continue; using namespace boost::asio::ip; if (pp.ip && pp.ip->is_unspecified()) + { *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()}; + } if (!pp.port) Throw("Use fixConfigPorts with auto ports"); diff --git a/src/test/jtx/impl/Oracle.cpp b/src/test/jtx/impl/Oracle.cpp index 9c75b21973..8bc456cd4e 100644 --- a/src/test/jtx/impl/Oracle.cpp +++ b/src/test/jtx/impl/Oracle.cpp @@ -12,7 +12,7 @@ namespace test { namespace jtx { namespace oracle { -Oracle::Oracle(Env& env, CreateArg const& arg, bool submit) : env_(env), owner_{}, documentID_{} +Oracle::Oracle(Env& env, CreateArg const& arg, bool submit) : env_(env), documentID_{} { // LastUpdateTime is checked to be in range // {close-maxLastUpdateTimeDelta, close+maxLastUpdateTimeDelta}. @@ -38,11 +38,17 @@ Oracle::remove(RemoveArg const& arg) jv[jss::Account] = to_string(arg.owner.value_or(owner_)); toJson(jv[jss::OracleDocumentID], arg.documentID.value_or(documentID_)); if (Oracle::fee != 0) + { jv[jss::Fee] = std::to_string(Oracle::fee); + } else if (arg.fee != 0) + { jv[jss::Fee] = std::to_string(arg.fee); + } else + { jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops()); + } if (arg.flags != 0) jv[jss::Flags] = arg.flags; submit(jv, arg.msig, arg.seq, arg.err); @@ -58,22 +64,38 @@ Oracle::submit( if (msig) { if (seq && err) + { env_(jv, *msig, *seq, *err); + } else if (seq) + { env_(jv, *msig, *seq); + } else if (err) + { env_(jv, *msig, *err); + } else + { env_(jv, *msig); + } } else if (seq && err) + { env_(jv, *seq, *err); + } else if (seq) + { env_(jv, *seq); + } else if (err) + { env_(jv, *err); + } else + { env_(jv); + } env_.close(); } @@ -90,7 +112,7 @@ Oracle::expectPrice(DataSeries const& series) const if (auto const sle = env_.le(keylet::oracle(owner_, documentID_))) { auto const& leSeries = sle->getFieldArray(sfPriceDataSeries); - if (leSeries.size() == 0 || leSeries.size() != series.size()) + if (leSeries.empty() || leSeries.size() != series.size()) return false; for (auto const& data : series) { @@ -157,9 +179,13 @@ Oracle::aggregatePrice( if (jr.isObject()) { if (jr.isMember(jss::result) && jr[jss::result].isMember(jss::status)) + { return jr[jss::result]; - else if (jr.isMember(jss::error)) + } + if (jr.isMember(jss::error)) + { return jr; + } } return Json::nullValue; } @@ -177,9 +203,13 @@ Oracle::set(UpdateArg const& arg) jv[jss::OracleDocumentID] = documentID_; } else if (arg.documentID) + { toJson(jv[jss::OracleDocumentID], *arg.documentID); + } else + { jv[jss::OracleDocumentID] = documentID_; + } jv[jss::TransactionType] = jss::OracleSet; jv[jss::Account] = to_string(owner_); if (arg.assetClass) @@ -191,24 +221,36 @@ Oracle::set(UpdateArg const& arg) if (arg.flags != 0) jv[jss::Flags] = arg.flags; if (Oracle::fee != 0) + { jv[jss::Fee] = std::to_string(Oracle::fee); + } else if (arg.fee != 0) + { jv[jss::Fee] = std::to_string(arg.fee); + } else + { jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops()); + } // lastUpdateTime if provided is offset from testStartTime if (arg.lastUpdateTime) { if (std::holds_alternative(*arg.lastUpdateTime)) + { jv[jss::LastUpdateTime] = to_string(testStartTime.count() + std::get(*arg.lastUpdateTime)); + } else + { toJson(jv[jss::LastUpdateTime], *arg.lastUpdateTime); + } } else + { jv[jss::LastUpdateTime] = to_string( duration_cast(env_.current()->header().closeTime.time_since_epoch()).count() + epoch_offset.count()); + } Json::Value dataSeries(Json::arrayValue); auto assetToStr = [](std::string const& s) { // assume standard currency @@ -225,8 +267,10 @@ Oracle::set(UpdateArg const& arg) price[jss::BaseAsset] = assetToStr(std::get<0>(data)); price[jss::QuoteAsset] = assetToStr(std::get<1>(data)); if (std::get<2>(data)) + { price[jss::AssetPrice] = *std::get<2>(data); // NOLINT(bugprone-unchecked-optional-access) + } if (std::get<3>(data)) price[jss::Scale] = *std::get<3>(data); // NOLINT(bugprone-unchecked-optional-access) priceData[jss::PriceData] = price; @@ -265,9 +309,13 @@ Oracle::ledgerEntry( if (account) { if (std::holds_alternative(*account)) + { jvParams[jss::oracle][jss::account] = to_string(std::get(*account)); + } else + { jvParams[jss::oracle][jss::account] = std::get(*account); + } } if (documentID) toJson(jvParams[jss::oracle][jss::oracle_document_id], *documentID); @@ -275,9 +323,13 @@ Oracle::ledgerEntry( { std::uint32_t i = 0; if (boost::conversion::try_lexical_convert(*index, i)) + { jvParams[jss::oracle][jss::ledger_index] = i; + } else + { jvParams[jss::oracle][jss::ledger_index] = *index; + } } // Convert "%None%" to None auto str = to_string(jvParams); @@ -308,12 +360,18 @@ toJsonHex(Json::Value& jv, AnyValue const& v) if constexpr (std::is_same_v) { if (arg.starts_with("##")) + { jv = arg.substr(2); + } else + { jv = strHex(arg); + } } else + { jv = arg; + } }, v); } diff --git a/src/test/jtx/impl/WSClient.cpp b/src/test/jtx/impl/WSClient.cpp index a51357c9b5..ebe4721d60 100644 --- a/src/test/jtx/impl/WSClient.cpp +++ b/src/test/jtx/impl/WSClient.cpp @@ -49,8 +49,10 @@ class WSClientImpl : public WSClient continue; using namespace boost::asio::ip; if (pp.ip && pp.ip->is_unspecified()) + { *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()}; + } if (!pp.port) Throw("Use fixConfigPorts with auto ports"); @@ -178,7 +180,9 @@ public: jp[jss::id] = 5; } else + { jp[jss::command] = cmd; + } auto const s = to_string(jp); ws_.write_some(true, buffer(s)); } diff --git a/src/test/jtx/impl/amount.cpp b/src/test/jtx/impl/amount.cpp index 4952334fe8..25fcb5c8f0 100644 --- a/src/test/jtx/impl/amount.cpp +++ b/src/test/jtx/impl/amount.cpp @@ -62,9 +62,13 @@ operator<<(std::ostream& os, PrettyAmount const& amount) if (n < c) { if (amount.value().negative()) + { os << "-" << n << " drops"; + } else + { os << n << " drops"; + } return os; } auto const d = double(n) / dropsPerXRP.drops(); diff --git a/src/test/jtx/impl/balance.cpp b/src/test/jtx/impl/balance.cpp index a136b19bdb..1c3cc0b3c3 100644 --- a/src/test/jtx/impl/balance.cpp +++ b/src/test/jtx/impl/balance.cpp @@ -66,7 +66,7 @@ doBalance( void balance::operator()(Env& env) const { - return std::visit( + std::visit( [&](auto const& issue) { doBalance(env, account_.id(), none_, value_, issue); }, value_.asset().value()); } diff --git a/src/test/jtx/impl/directory.cpp b/src/test/jtx/impl/directory.cpp index 7231389d1e..bf63bc523b 100644 --- a/src/test/jtx/impl/directory.cpp +++ b/src/test/jtx/impl/directory.cpp @@ -72,7 +72,9 @@ bumpLastPage( // Adjust root previous and previous node's next sleRoot->setFieldU64(sfIndexPrevious, newLastPage); if (prevIndex.value_or(0) == 0) + { sleRoot->setFieldU64(sfIndexNext, newLastPage); + } else { auto slePrev = sb.peek(keylet::page(directory, *prevIndex)); @@ -88,6 +90,7 @@ bumpLastPage( // Fixup page numbers in the objects referred by indexes if (adjust) + { for (auto const key : indexes) { if (!adjust(sb, key, newLastPage)) @@ -96,6 +99,7 @@ bumpLastPage( return false; } } + } sb.apply(view); return true; diff --git a/src/test/jtx/impl/fee.cpp b/src/test/jtx/impl/fee.cpp index 2b1ac6c398..fc05afcb46 100644 --- a/src/test/jtx/impl/fee.cpp +++ b/src/test/jtx/impl/fee.cpp @@ -14,9 +14,13 @@ fee::operator()(Env& env, JTx& jt) const jt.fill_fee = false; assert(!increment_ || !amount_); if (increment_) + { jt[sfFee] = STAmount(env.current()->fees().increment).getJson(); + } else if (amount_) + { jt[sfFee] = amount_->getJson(JsonOptions::none); + } } } // namespace jtx diff --git a/src/test/jtx/impl/flags.cpp b/src/test/jtx/impl/flags.cpp index 11e7831f55..aee01a107e 100644 --- a/src/test/jtx/impl/flags.cpp +++ b/src/test/jtx/impl/flags.cpp @@ -24,11 +24,17 @@ flags::operator()(Env& env) const { auto const sle = env.le(account_); if (!sle) + { env.test.fail(); + } else if (sle->isFieldPresent(sfFlags)) + { env.test.expect((sle->getFieldU32(sfFlags) & mask_) == mask_); + } else + { env.test.expect(mask_ == 0); + } } void @@ -36,11 +42,17 @@ nflags::operator()(Env& env) const { auto const sle = env.le(account_); if (!sle) + { env.test.fail(); + } else if (sle->isFieldPresent(sfFlags)) + { env.test.expect((sle->getFieldU32(sfFlags) & mask_) == 0); + } else + { env.test.pass(); + } } } // namespace jtx diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index c1cde76896..b6b08734c7 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -77,12 +77,14 @@ static MPTCreate makeMPTCreate(MPTInitDef const& arg) { if (arg.pay) + { return { .maxAmt = arg.maxAmt, .transferFee = arg.transferFee, .pay = {{arg.holders, *arg.pay}}, .flags = arg.flags, .authHolder = arg.authHolder}; + } return { .maxAmt = arg.maxAmt, .transferFee = arg.transferFee, @@ -174,16 +176,24 @@ MPTTester::create(MPTCreate const& arg) if (arg.authorize) { if (arg.authorize->empty()) + { authAndPay(holders_, [](auto const& it) { return it.second; }); + } else + { authAndPay(*arg.authorize, [](auto const& it) { return it; }); + } } else if (arg.pay) { if (arg.pay->first.empty()) + { authAndPay(holders_, [](auto const& it) { return it.second; }); + } else + { authAndPay(arg.pay->first, [](auto const& it) { return it; }); + } } } } @@ -253,10 +263,14 @@ MPTTester::authorize(MPTAuthorize const& arg) auto const flags = getFlags(arg.holder); // issuer un-authorizes the holder if (arg.flags.value_or(0) == tfMPTUnauthorize) + { env_.require(mptflags(*this, flags, arg.holder)); - // issuer authorizes the holder + // issuer authorizes the holder + } else + { env_.require(mptflags(*this, flags | lsfMPTAuthorized, arg.holder)); + } } // Holder authorizes else if (arg.flags.value_or(0) != tfMPTUnauthorize) @@ -315,9 +329,13 @@ MPTTester::setJV(MPTSet const& arg) std::visit( [&jv](T const& holder) { if constexpr (std::is_same_v) + { jv[sfHolder] = holder.human(); + } else if constexpr (std::is_same_v) + { jv[sfHolder] = toBase58(holder); + } }, *arg.holder); } @@ -360,42 +378,70 @@ MPTTester::set(MPTSet const& arg) if (arg.flags) { if (*arg.flags & tfMPTLock) + { flags |= lsfMPTLocked; + } else if (*arg.flags & tfMPTUnlock) + { flags &= ~lsfMPTLocked; + } } if (arg.mutableFlags) { if (*arg.mutableFlags & tmfMPTSetCanLock) + { flags |= lsfMPTCanLock; + } else if (*arg.mutableFlags & tmfMPTClearCanLock) + { flags &= ~lsfMPTCanLock; + } if (*arg.mutableFlags & tmfMPTSetRequireAuth) + { flags |= lsfMPTRequireAuth; + } else if (*arg.mutableFlags & tmfMPTClearRequireAuth) + { flags &= ~lsfMPTRequireAuth; + } if (*arg.mutableFlags & tmfMPTSetCanEscrow) + { flags |= lsfMPTCanEscrow; + } else if (*arg.mutableFlags & tmfMPTClearCanEscrow) + { flags &= ~lsfMPTCanEscrow; + } if (*arg.mutableFlags & tmfMPTSetCanClawback) + { flags |= lsfMPTCanClawback; + } else if (*arg.mutableFlags & tmfMPTClearCanClawback) + { flags &= ~lsfMPTCanClawback; + } if (*arg.mutableFlags & tmfMPTSetCanTrade) + { flags |= lsfMPTCanTrade; + } else if (*arg.mutableFlags & tmfMPTClearCanTrade) + { flags &= ~lsfMPTCanTrade; + } if (*arg.mutableFlags & tmfMPTSetCanTransfer) + { flags |= lsfMPTCanTransfer; + } else if (*arg.mutableFlags & tmfMPTClearCanTransfer) + { flags &= ~lsfMPTCanTransfer; + } } } env_.require(mptflags(*this, flags, holder)); @@ -498,12 +544,16 @@ MPTTester::pay( auto const outstandingAmt = getBalance(issuer_); if (credentials) + { env_( jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS)), credentials::ids(*credentials)); + } else + { env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS))); + } if (!isTesSuccess(env_.ter())) amount = 0; diff --git a/src/test/jtx/impl/multisign.cpp b/src/test/jtx/impl/multisign.cpp index 54bde3ebb9..ae39382824 100644 --- a/src/test/jtx/impl/multisign.cpp +++ b/src/test/jtx/impl/multisign.cpp @@ -53,9 +53,13 @@ msig::operator()(Env& env, JTx& jt) const // The signing pub key is only required at the top level. if (!subField) + { sigObject[sfSigningPubKey] = ""; + } else if (sigObject.isNull()) + { sigObject = Json::Value(Json::objectValue); + } std::optional st; try { @@ -80,9 +84,13 @@ msig::operator()(Env& env, JTx& jt) const } }; if (!subField) + { jt.mainSigners.emplace_back(callback); + } else + { jt.postSigners.emplace_back(callback); + } } } // namespace jtx diff --git a/src/test/jtx/impl/sig.cpp b/src/test/jtx/impl/sig.cpp index 3ea7f669a7..850c5af781 100644 --- a/src/test/jtx/impl/sig.cpp +++ b/src/test/jtx/impl/sig.cpp @@ -23,9 +23,13 @@ sig::operator()(Env&, JTx& jt) const jtx::sign(jtx.jv, account, sigObject); }; if (!subField_) + { jt.mainSigners.emplace_back(callback); + } else + { jt.postSigners.emplace_back(callback); + } } } diff --git a/src/test/jtx/impl/vault.cpp b/src/test/jtx/impl/vault.cpp index 90250aece0..49c0dddaec 100644 --- a/src/test/jtx/impl/vault.cpp +++ b/src/test/jtx/impl/vault.cpp @@ -12,7 +12,7 @@ namespace test { namespace jtx { std::tuple -Vault::create(CreateArgs const& args) +Vault::create(CreateArgs const& args) const { auto keylet = keylet::vault(args.owner.id(), env.seq(args.owner)); Json::Value jv; diff --git a/src/test/jtx/impl/xchain_bridge.cpp b/src/test/jtx/impl/xchain_bridge.cpp index dfd7f0ba96..c2617f5073 100644 --- a/src/test/jtx/impl/xchain_bridge.cpp +++ b/src/test/jtx/impl/xchain_bridge.cpp @@ -286,6 +286,7 @@ claim_attestations( JValueVec vec; vec.reserve(numAtts); for (auto i = fromIdx; i < fromIdx + numAtts; ++i) + { vec.emplace_back(claim_attestation( submittingAccount, jvBridge, @@ -296,6 +297,7 @@ claim_attestations( claimID, dst, signers[i])); + } return vec; } @@ -319,6 +321,7 @@ create_account_attestations( JValueVec vec; vec.reserve(numAtts); for (auto i = fromIdx; i < fromIdx + numAtts; ++i) + { vec.emplace_back(create_account_attestation( submittingAccount, jvBridge, @@ -330,6 +333,7 @@ create_account_attestations( createCount, dst, signers[i])); + } return vec; } diff --git a/src/test/jtx/vault.h b/src/test/jtx/vault.h index 65a5706354..43f975323a 100644 --- a/src/test/jtx/vault.h +++ b/src/test/jtx/vault.h @@ -30,7 +30,7 @@ struct Vault /** Return a VaultCreate transaction and the Vault's expected keylet. */ std::tuple - create(CreateArgs const& args); + create(CreateArgs const& args) const; struct SetArgs { diff --git a/src/test/ledger/BookDirs_test.cpp b/src/test/ledger/BookDirs_test.cpp index 50f1bb46ba..d7841fe502 100644 --- a/src/test/ledger/BookDirs_test.cpp +++ b/src/test/ledger/BookDirs_test.cpp @@ -56,8 +56,10 @@ struct BookDirs_test : public beast::unit_test::suite { auto AUD = gw["AUD"]; for (auto i = 1, j = 3; i <= 3; ++i, --j) + { for (auto k = 0; k < 80; ++k) env(offer("alice", AUD(i), XRP(j))); + } auto d = BookDirs(*env.current(), Book(AUD.issue(), xrpIssue(), std::nullopt)); BEAST_EXPECT(std::distance(d.begin(), d.end()) == 240); diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index 8e7ba38c53..ec76b67e9c 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -46,14 +46,22 @@ struct Directory_test : public beast::unit_test::suite p->setFieldV256(sfIndexes, STVector256{}); if (i + 1 == n) + { p->setFieldU64(sfIndexNext, 0); + } else + { p->setFieldU64(sfIndexNext, i + 1); + } if (i == 0) + { p->setFieldU64(sfIndexPrevious, n - 1); + } else + { p->setFieldU64(sfIndexPrevious, i - 1); + } sb.insert(p); } @@ -254,8 +262,10 @@ struct Directory_test : public beast::unit_test::suite // Fill up three pages of offers for (int i = 0; i < 3; ++i) + { for (int j = 0; j < dirNodeMaxEntries; ++j) env(offer(alice, XRP(1), USD(1))); + } env.close(); // remove all the offers. Remove the middle page last diff --git a/src/test/nodestore/Timing_test.cpp b/src/test/nodestore/Timing_test.cpp index e334283052..d5c89dbcc9 100644 --- a/src/test/nodestore/Timing_test.cpp +++ b/src/test/nodestore/Timing_test.cpp @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -621,8 +622,9 @@ public: using std::setw; int w = 8; for (auto const& test : tests) - if (w < test.first.size()) - w = test.first.size(); + { + w = std::max::size_type>(w, test.first.size()); + } log << threads << " Thread" << (threads > 1 ? "s" : "") << ", " << default_items << " Objects" << std::endl; { @@ -649,8 +651,10 @@ public: std::stringstream ss; ss << std::left << setw(10) << get(config, "type", std::string()) << std::right; for (auto const& test : tests) + { ss << " " << setw(w) << to_string(do_test(test.second, config, params, journal)); + } ss << " " << to_string(config); log << ss.str() << std::endl; } @@ -690,10 +694,16 @@ public: std::vector config_strings; boost::split(config_strings, args, boost::algorithm::is_any_of(";")); for (auto iter = config_strings.begin(); iter != config_strings.end();) + { if (iter->empty()) + { iter = config_strings.erase(iter); + } else + { ++iter; + } + } do_tests(1, tests, config_strings); do_tests(4, tests, config_strings); diff --git a/src/test/nodestore/import_test.cpp b/src/test/nodestore/import_test.cpp index 2177646eaa..e5f281486b 100644 --- a/src/test/nodestore/import_test.cpp +++ b/src/test/nodestore/import_test.cpp @@ -367,8 +367,10 @@ public: for (it->SeekToFirst(); it->Valid(); it->Next()) { if (it->key().size() != 32) + { Throw( "Unexpected key size " + std::to_string(it->key().size())); + } void const* const key = it->key().data(); void const* const data = it->value().data(); auto const size = it->value().size(); diff --git a/src/test/overlay/compression_test.cpp b/src/test/overlay/compression_test.cpp index 3c787a4c72..f784a91350 100644 --- a/src/test/overlay/compression_test.cpp +++ b/src/test/overlay/compression_test.cpp @@ -176,7 +176,7 @@ public: return std::string{reinterpret_cast(blob->data()), blob->size()}; }; - std::string usdTxBlob = ""; + std::string usdTxBlob; auto wsc = makeWSClient(env.app().config()); { Json::Value requestUSD; diff --git a/src/test/overlay/reduce_relay_test.cpp b/src/test/overlay/reduce_relay_test.cpp index 7e105e9f85..8e50415aa9 100644 --- a/src/test/overlay/reduce_relay_test.cpp +++ b/src/test/overlay/reduce_relay_test.cpp @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -404,7 +405,7 @@ public: } std::uint16_t - id() + id() const { return id_; } @@ -482,9 +483,13 @@ public: auto validator = squelch.validatorpubkey(); PublicKey key(Slice(validator.data(), validator.size())); if (squelch.squelch()) + { squelch_.addSquelch(key, std::chrono::seconds{squelch.squelchduration()}); + } else + { squelch_.removeSquelch(key); + } } private: @@ -601,8 +606,7 @@ public: for (auto& [id, _] : peers_) { (void)_; - if (id > maxId) - maxId = id; + maxId = std::max(id, maxId); } deletePeer(maxId, false); @@ -626,7 +630,7 @@ public: isSelected(PublicKey const& validator, Peer::id_t peer) { auto selected = slots_.getSelected(validator); - return selected.find(peer) != selected.end(); + return selected.contains(peer); } id_t @@ -752,9 +756,13 @@ public: validators_.begin(), validators_.end(), [&](auto& v) { return v.id() == validatorId; }); assert(it != validators_.end()); if (enable) + { it->linkUp(peer); + } else + { it->linkDown(peer); + } } void @@ -940,9 +948,11 @@ protected: for (auto s : selected) str << s << " "; if (log) + { std::cout << (double)reduce_relay::epoch(now).count() / 1000. << " random, squelched, validator: " << validator.id() << " peers: " << str.str() << std::endl; + } auto countingState = network_.overlay().isCountingState(validator); BEAST_EXPECT( countingState == false && @@ -968,7 +978,9 @@ protected: network_.overlay().isSelected(validator, link.peerId()); } else + { events[event].isSelected_ = network_.isSelected(link.peerId()); + } }; auto r = rand_int(0, 1000); if (r == (int)EventType::LinkDown || r == (int)EventType::PeerDisconnected) @@ -1025,7 +1037,7 @@ protected: d > milliseconds(reduce_relay::IDLED).count() && network_.overlay().inState( *event.key_, reduce_relay::PeerState::Squelched) > 0 && - peers.find(event.peer_) != peers.end(); + peers.contains(event.peer_); } network_.overlay().deleteIdlePeers([&](PublicKey const& v, PeerWPtr const& ptr) { event.handled_ = true; @@ -1060,9 +1072,11 @@ protected: // All Peer Disconnect events must be handled BEAST_EXPECT(disconnected.cnt_ == disconnected.handledCnt_); if (log) + { std::cout << "link down count: " << down.cnt_ << "/" << down.handledCnt_ << " peer disconnect count: " << disconnected.cnt_ << "/" << disconnected.handledCnt_; + } } bool @@ -1455,8 +1469,7 @@ vp_base_squelch_max_selected_peers=2 void squelch(PublicKey const&, Peer::id_t, std::uint32_t duration) const override { - if (duration > maxDuration_) - maxDuration_ = duration; + maxDuration_ = std::max(duration, maxDuration_); } void unsquelch(PublicKey const&, Peer::id_t) const override @@ -1519,18 +1532,22 @@ vp_base_squelch_max_selected_peers=2 handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count()); using namespace beast::unit_test::detail; if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count()) + { log << make_reason("warning: squelch duration is low", __FILE__, __LINE__) << std::endl << std::flush; + } // more than 400 is still less than MAX_UNSQUELCH_EXPIRE_PEERS run(400); BEAST_EXPECT( handler.maxDuration_ >= MIN_UNSQUELCH_EXPIRE.count() && handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_PEERS.count()); if (handler.maxDuration_ <= MAX_UNSQUELCH_EXPIRE_DEFAULT.count()) + { log << make_reason("warning: squelch duration is low", __FILE__, __LINE__) << std::endl << std::flush; + } }); } diff --git a/src/test/overlay/short_read_test.cpp b/src/test/overlay/short_read_test.cpp index bff0bd82cb..d96f67c8a1 100644 --- a/src/test/overlay/short_read_test.cpp +++ b/src/test/overlay/short_read_test.cpp @@ -180,7 +180,10 @@ private: close() override { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&Acceptor::close, shared_from_this())); + { + post(strand_, std::bind(&Acceptor::close, shared_from_this())); + return; + } acceptor_.close(); } @@ -210,7 +213,10 @@ private: on_accept(error_code ec) { if (ec) - return fail("accept", ec); + { + fail("accept", ec); + return; + } auto const p = std::make_shared(server_, std::move(socket_)); server_.add(p); p->run(); @@ -248,7 +254,10 @@ private: close() override { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&Connection::close, shared_from_this())); + { + post(strand_, std::bind(&Connection::close, shared_from_this())); + return; + } if (socket_.is_open()) { socket_.close(); @@ -289,7 +298,10 @@ private: if (ec == boost::asio::error::operation_aborted) return; if (ec) - return fail("timer", ec); + { + fail("timer", ec); + return; + } test_.log << "[server] timeout" << std::endl; socket_.close(); } @@ -298,7 +310,10 @@ private: on_handshake(error_code ec) { if (ec) - return fail("handshake", ec); + { + fail("handshake", ec); + return; + } #if 1 boost::asio::async_read_until( stream_, @@ -322,13 +337,17 @@ private: if (ec == boost::asio::error::eof) { server_.test_.log << "[server] read: EOF" << std::endl; - return stream_.async_shutdown(bind_executor( + stream_.async_shutdown(bind_executor( strand_, std::bind( &Connection::on_shutdown, shared_from_this(), std::placeholders::_1))); + return; } if (ec) - return fail("read", ec); + { + fail("read", ec); + return; + } buf_.commit(bytes_transferred); buf_.consume(bytes_transferred); @@ -350,7 +369,10 @@ private: { buf_.consume(bytes_transferred); if (ec) - return fail("write", ec); + { + fail("write", ec); + return; + } stream_.async_shutdown(bind_executor( strand_, std::bind( @@ -361,7 +383,10 @@ private: on_shutdown(error_code ec) { if (ec) - return fail("shutdown", ec); + { + fail("shutdown", ec); + return; + } socket_.close(); timer_.cancel(); } @@ -422,7 +447,10 @@ private: close() override { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&Connection::close, shared_from_this())); + { + post(strand_, std::bind(&Connection::close, shared_from_this())); + return; + } if (socket_.is_open()) { socket_.close(); @@ -463,7 +491,10 @@ private: if (ec == boost::asio::error::operation_aborted) return; if (ec) - return fail("timer", ec); + { + fail("timer", ec); + return; + } test_.log << "[client] timeout"; socket_.close(); } @@ -472,7 +503,10 @@ private: on_connect(error_code ec) { if (ec) - return fail("connect", ec); + { + fail("connect", ec); + return; + } stream_.async_handshake( stream_type::client, bind_executor( @@ -485,7 +519,10 @@ private: on_handshake(error_code ec) { if (ec) - return fail("handshake", ec); + { + fail("handshake", ec); + return; + } write(buf_, "HELLO\n"); #if 1 @@ -512,7 +549,10 @@ private: { buf_.consume(bytes_transferred); if (ec) - return fail("write", ec); + { + fail("write", ec); + return; + } #if 1 boost::asio::async_read_until( stream_, @@ -537,7 +577,10 @@ private: on_read(error_code ec, std::size_t bytes_transferred) { if (ec) - return fail("read", ec); + { + fail("read", ec); + return; + } buf_.commit(bytes_transferred); stream_.async_shutdown(bind_executor( strand_, @@ -549,7 +592,10 @@ private: on_shutdown(error_code ec) { if (ec) - return fail("shutdown", ec); + { + fail("shutdown", ec); + return; + } socket_.close(); timer_.cancel(); } diff --git a/src/test/overlay/tx_reduce_relay_test.cpp b/src/test/overlay/tx_reduce_relay_test.cpp index e3facb2f76..11b5c95a4e 100644 --- a/src/test/overlay/tx_reduce_relay_test.cpp +++ b/src/test/overlay/tx_reduce_relay_test.cpp @@ -53,16 +53,24 @@ private: BEAST_EXPECT(c.TX_REDUCE_RELAY_MIN_PEERS == min); BEAST_EXPECT(c.TX_RELAY_PERCENTAGE == pct); if (success) + { pass(); + } else + { fail(); + } } catch (...) { if (success) + { fail(); + } else + { pass(); + } } }; @@ -146,8 +154,7 @@ private: auto& overlay = dynamic_cast(env.app().overlay()); boost::beast::http::request request; (nDisabled == 0) - ? (void)request.insert( - "X-Protocol-Ctl", makeFeaturesRequestHeader(false, false, true, false)) + ? request.insert("X-Protocol-Ctl", makeFeaturesRequestHeader(false, false, true, false)) : (void)nDisabled--; auto stream_ptr = std::make_unique( socket_type(std::forward(env.app().getIOContext())), diff --git a/src/test/peerfinder/Livecache_test.cpp b/src/test/peerfinder/Livecache_test.cpp index a69a300686..b2d0eeeaf1 100644 --- a/src/test/peerfinder/Livecache_test.cpp +++ b/src/test/peerfinder/Livecache_test.cpp @@ -30,7 +30,7 @@ public: // Add the address as an endpoint template - inline void + void add(beast::IP::Endpoint ep, C& c, std::uint32_t hops = 0) { Endpoint cep{ep, hops}; diff --git a/src/test/peerfinder/PeerFinder_test.cpp b/src/test/peerfinder/PeerFinder_test.cpp index 038ed438f0..c39564c54c 100644 --- a/src/test/peerfinder/PeerFinder_test.cpp +++ b/src/test/peerfinder/PeerFinder_test.cpp @@ -391,7 +391,7 @@ public: testcase(test); - std::string toLoad = ""; + std::string toLoad; int max = 0; if (maxPeers) { diff --git a/src/test/protocol/STAccount_test.cpp b/src/test/protocol/STAccount_test.cpp index cab5df9631..3b12605a92 100644 --- a/src/test/protocol/STAccount_test.cpp +++ b/src/test/protocol/STAccount_test.cpp @@ -12,7 +12,7 @@ struct STAccount_test : public beast::unit_test::suite // Test default constructor. STAccount const defaultAcct; BEAST_EXPECT(defaultAcct.getSType() == STI_ACCOUNT); - BEAST_EXPECT(defaultAcct.getText() == ""); + BEAST_EXPECT(defaultAcct.getText().empty()); BEAST_EXPECT(defaultAcct.isDefault() == true); BEAST_EXPECT(defaultAcct.value() == AccountID{}); { @@ -38,7 +38,7 @@ struct STAccount_test : public beast::unit_test::suite // Test constructor from SField. STAccount const sfAcct{sfAccount}; BEAST_EXPECT(sfAcct.getSType() == STI_ACCOUNT); - BEAST_EXPECT(sfAcct.getText() == ""); + BEAST_EXPECT(sfAcct.getText().empty()); BEAST_EXPECT(sfAcct.isDefault()); BEAST_EXPECT(sfAcct.value() == AccountID{}); BEAST_EXPECT(sfAcct.isEquivalent(defaultAcct)); diff --git a/src/test/protocol/STObject_test.cpp b/src/test/protocol/STObject_test.cpp index b809ffccad..0faa1946a9 100644 --- a/src/test/protocol/STObject_test.cpp +++ b/src/test/protocol/STObject_test.cpp @@ -420,9 +420,9 @@ public: STObject st(sot, sfGeneric); auto const& cst(st); - BEAST_EXPECT(cst[sf1].size() == 0); + BEAST_EXPECT(cst[sf1].empty()); BEAST_EXPECT(!cst[~sf2]); - BEAST_EXPECT(cst[sf3].size() == 0); + BEAST_EXPECT(cst[sf3].empty()); std::vector v; v.emplace_back(1); st[sf1] = v; @@ -437,7 +437,7 @@ public: BEAST_EXPECT(cst[sf3].size() == 1); BEAST_EXPECT(cst[sf3][0] == uint256{1}); st[sf3] = std::vector{}; - BEAST_EXPECT(cst[sf3].size() == 0); + BEAST_EXPECT(cst[sf3].empty()); } } // namespace xrpl diff --git a/src/test/protocol/STParsedJSON_test.cpp b/src/test/protocol/STParsedJSON_test.cpp index 97da346015..18e695d25d 100644 --- a/src/test/protocol/STParsedJSON_test.cpp +++ b/src/test/protocol/STParsedJSON_test.cpp @@ -894,7 +894,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfPublicKey)); auto const& blob = obj.object->getFieldVL(sfPublicKey); // NOLINT(bugprone-unchecked-optional-access) - BEAST_EXPECT(blob.size() == 0); + BEAST_EXPECT(blob.empty()); } // Test lowercase hex string for blob @@ -975,7 +975,7 @@ class STParsedJSON_test : public beast::unit_test::suite BEAST_EXPECT(obj.object->isFieldPresent(sfHashes)); auto const& vec = obj.object->getFieldV256(sfHashes); // NOLINT(bugprone-unchecked-optional-access) - BEAST_EXPECT(vec.size() == 0); + BEAST_EXPECT(vec.empty()); } // Test array with invalid hex string (should fail) diff --git a/src/test/protocol/SecretKey_test.cpp b/src/test/protocol/SecretKey_test.cpp index 43065d4e40..e42bec3363 100644 --- a/src/test/protocol/SecretKey_test.cpp +++ b/src/test/protocol/SecretKey_test.cpp @@ -112,7 +112,7 @@ public: auto sig = signDigest(pk, sk, digest); - BEAST_EXPECT(sig.size() != 0); + BEAST_EXPECT(!sig.empty()); BEAST_EXPECT(verifyDigest(pk, digest, sig, true)); // Wrong digest: @@ -150,7 +150,7 @@ public: auto sig = sign(pk, sk, makeSlice(data)); - BEAST_EXPECT(sig.size() != 0); + BEAST_EXPECT(!sig.empty()); BEAST_EXPECT(verify(pk, makeSlice(data), sig)); // Construct wrong data: diff --git a/src/test/protocol/Seed_test.cpp b/src/test/protocol/Seed_test.cpp index d516ec3e59..d7ad1f4afa 100644 --- a/src/test/protocol/Seed_test.cpp +++ b/src/test/protocol/Seed_test.cpp @@ -120,7 +120,7 @@ public: to_string(calcNodeID(publicKey)) == "7E59C17D50F5959C7B158FEC95C8F815BF653DC8"); auto sig = sign(publicKey, secretKey, makeSlice(message1)); - BEAST_EXPECT(sig.size() != 0); + BEAST_EXPECT(!sig.empty()); BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig)); // Correct public key but wrong message @@ -162,7 +162,7 @@ public: to_string(calcNodeID(publicKey)) == "AA066C988C712815CC37AF71472B7CBBBD4E2A0A"); auto sig = sign(publicKey, secretKey, makeSlice(message1)); - BEAST_EXPECT(sig.size() != 0); + BEAST_EXPECT(!sig.empty()); BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig)); // Correct public key but wrong message @@ -202,7 +202,7 @@ public: "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh"); auto sig = sign(pk, sk, makeSlice(message1)); - BEAST_EXPECT(sig.size() != 0); + BEAST_EXPECT(!sig.empty()); BEAST_EXPECT(verify(pk, makeSlice(message1), sig)); // Correct public key but wrong message @@ -241,7 +241,7 @@ public: "pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9"); auto sig = sign(pk, sk, makeSlice(message1)); - BEAST_EXPECT(sig.size() != 0); + BEAST_EXPECT(!sig.empty()); BEAST_EXPECT(verify(pk, makeSlice(message1), sig)); // Correct public key but wrong message diff --git a/src/test/resource/Logic_test.cpp b/src/test/resource/Logic_test.cpp index de57c715bc..c555b92860 100644 --- a/src/test/resource/Logic_test.cpp +++ b/src/test/resource/Logic_test.cpp @@ -66,9 +66,13 @@ public: testDrop(beast::Journal j, bool limited) { if (limited) + { testcase("Limited warn/drop"); + } else + { testcase("Unlimited warn/drop"); + } TestLogic logic(j); @@ -90,18 +94,26 @@ public: if (n == 0) { if (limited) + { fail("Loop count exceeded without warning"); + } else + { pass(); + } return; } if (c.charge(fee) == warn) { if (limited) + { pass(); + } else + { fail("Should loop forever with no warning"); + } break; } ++logic.clock(); @@ -113,9 +125,13 @@ public: if (n == 0) { if (limited) + { fail("Loop count exceeded without dropping"); + } else + { pass(); + } return; } @@ -136,9 +152,13 @@ public: if (c.disposition() != drop) { if (limited) + { fail("Dropped consumer not put on blacklist"); + } else + { pass(); + } return; } } diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index d3be04ff96..3f20e0378d 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -23,11 +23,15 @@ public: enum TestAccount { None, Alice, Bogie }; auto accountId = [&](AMM const& ammAlice, TestAccount v) -> std::optional { if (v == Alice) + { return ammAlice.ammAccount(); - else if (v == Bogie) + } + if (v == Bogie) + { return bogie; - else - return std::nullopt; + } + + return std::nullopt; }; // Invalid tokens pair @@ -185,9 +189,13 @@ public: Account a(std::to_string(i)); votes.insert({a.human(), 50 * (i + 1)}); if (!features[fixAMMv1_3]) + { fund(env, gw, {a}, {USD(10000)}, Fund::Acct); + } else + { fund(env, gw, {a}, {USD(10001)}, Fund::Acct); + } ammAlice.deposit(a, 10000000); ammAlice.vote(a, 50 * (i + 1)); } @@ -197,6 +205,7 @@ public: env.fund(XRP(1000), bob, ed, bill); env(ammAlice.bid({.bidMin = 100, .authAccounts = {carol, bob, ed, bill}})); if (!features[fixAMMv1_3]) + { BEAST_EXPECT(ammAlice.expectAmmRpcInfo( XRP(80000), USD(80000), @@ -204,7 +213,9 @@ public: std::nullopt, std::nullopt, ammAlice.ammAccount())); + } else + { BEAST_EXPECT(ammAlice.expectAmmRpcInfo( XRPAmount(80000000005), STAmount{USD, UINT64_C(80'000'00000000005), -11}, @@ -212,6 +223,7 @@ public: std::nullopt, std::nullopt, ammAlice.ammAccount())); + } for (auto i = 0; i < 2; ++i) { std::unordered_set authAccounts = { diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 090f2a43b9..435bbd37d5 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -305,9 +305,13 @@ public: BEAST_EXPECT(aobjs.size() == 1); auto& aobj = aobjs[0U]; if (i < 3) + { BEAST_EXPECT(resp[jss::result][jss::limit] == 1); + } else + { BEAST_EXPECT(!resp[jss::result].isMember(jss::limit)); + } aobj.removeMember("PreviousTxnID"); aobj.removeMember("PreviousTxnLgrSeq"); diff --git a/src/test/rpc/AccountOffers_test.cpp b/src/test/rpc/AccountOffers_test.cpp index 55e60f8caa..6b93e0570f 100644 --- a/src/test/rpc/AccountOffers_test.cpp +++ b/src/test/rpc/AccountOffers_test.cpp @@ -13,7 +13,7 @@ public: checkMarker(Json::Value const& val) { return val.isMember(jss::marker) && val[jss::marker].isString() && - val[jss::marker].asString().size() > 0; + !val[jss::marker].asString().empty(); } void diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 5015b960f9..a11f957628 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -62,19 +62,24 @@ class AccountTx_test : public beast::unit_test::suite for (Json::Value const& metaNode : txNode[jss::meta][sfAffectedNodes.jsonName]) { if (metaNode.isMember(sfCreatedNode.jsonName)) + { createdNodes.insert( metaNode[sfCreatedNode.jsonName][sfLedgerEntryType.jsonName].asString()); - + } else if (metaNode.isMember(sfDeletedNode.jsonName)) + { deletedNodes.insert( metaNode[sfDeletedNode.jsonName][sfLedgerEntryType.jsonName].asString()); - + } else if (metaNode.isMember(sfModifiedNode.jsonName)) + { modifiedNodes.insert( metaNode[sfModifiedNode.jsonName][sfLedgerEntryType.jsonName].asString()); - + } else + { fail("Unexpected or unlabeled node type in metadata.", __FILE__, __LINE__); + } } BEAST_EXPECT(createdNodes == sane.created); @@ -138,7 +143,9 @@ class AccountTx_test : public beast::unit_test::suite (payment[jss::close_time_iso] == "2000-01-01T00:00:10Z"); } else + { return false; + } default: return false; @@ -177,18 +184,26 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index_min] = 0; p[jss::ledger_index_max] = 100; if (apiVersion < 2u) + { BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + } else + { BEAST_EXPECT( isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); + } p[jss::ledger_index_min] = 1; p[jss::ledger_index_max] = 2; if (apiVersion < 2u) + { BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p)))); + } else + { BEAST_EXPECT( isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); + } p[jss::ledger_index_min] = 2; p[jss::ledger_index_max] = 1; @@ -204,10 +219,14 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index_min] = 1; if (apiVersion < 2u) + { BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + } else + { BEAST_EXPECT( isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); + } p[jss::ledger_index_min] = env.current()->header().seq; BEAST_EXPECT(isErr( @@ -223,10 +242,14 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index_max] = env.current()->header().seq; if (apiVersion < 2u) + { BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + } else + { BEAST_EXPECT( isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); + } p[jss::ledger_index_max] = 3; BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); @@ -278,9 +301,13 @@ class AccountTx_test : public beast::unit_test::suite p[jss::ledger_index] = -1; if (apiVersion < 2u) + { BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + } else + { BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); + } } // Ledger index max only @@ -288,10 +315,14 @@ class AccountTx_test : public beast::unit_test::suite Json::Value p{jParams}; p[jss::ledger_index_max] = env.current()->header().seq; if (apiVersion < 2u) + { BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + } else + { BEAST_EXPECT( isErr(env.rpc("json", "account_tx", to_string(p)), rpcLGR_IDX_MALFORMED)); + } } // test account non-string { @@ -320,7 +351,9 @@ class AccountTx_test : public beast::unit_test::suite BEAST_EXPECT(result[jss::result][jss::status] == "success"); } else + { BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); + } p[jss::binary] = true; Json::Value result{env.rpc("json", "account_tx", to_string(p))}; @@ -328,9 +361,13 @@ class AccountTx_test : public beast::unit_test::suite p[jss::forward] = "true"; if (apiVersion < 2u) + { BEAST_EXPECT(result[jss::result][jss::status] == "success"); + } else + { BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), rpcINVALID_PARAMS)); + } p[jss::forward] = false; result = env.rpc("json", "account_tx", to_string(p)); diff --git a/src/test/rpc/DeliveredAmount_test.cpp b/src/test/rpc/DeliveredAmount_test.cpp index c156a566b0..00f8c54ee5 100644 --- a/src/test/rpc/DeliveredAmount_test.cpp +++ b/src/test/rpc/DeliveredAmount_test.cpp @@ -36,9 +36,13 @@ class CheckDeliveredAmount if (!afterSwitchTime_) { if (partial) + { ++numExpectedAvailable_; + } else + { ++numExpectedSetUnavailable_; + } return; } // normal case: after switch time & successful transaction @@ -91,16 +95,26 @@ public: if (isSet) { if (metaData[jss::delivered_amount] != "unavailable") + { isSetAvailable = true; + } else + { isSetUnavailable = true; + } } if (isSetAvailable) + { --numExpectedAvailable_; + } else if (isSetUnavailable) + { --numExpectedSetUnavailable_; + } else if (!isSet) + { --numExpectedNotSet_; + } if (isSet) { @@ -178,9 +192,13 @@ class DeliveredAmount_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob, carol, gw); env.trust(USD(1000), alice, bob, carol); if (afterSwitchTime) + { env.close(NetClock::time_point{446000000s}); + } else + { env.close(); + } CheckDeliveredAmount checkDeliveredAmount{afterSwitchTime}; { @@ -265,9 +283,13 @@ class DeliveredAmount_test : public beast::unit_test::suite env.fund(XRP(10000), alice, bob, carol, gw); env.trust(USD(1000), alice, bob, carol); if (afterSwitchTime) + { env.close(NetClock::time_point{446000000s}); + } else + { env.close(); + } CheckDeliveredAmount checkDeliveredAmount{afterSwitchTime}; // normal payments diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 9d6de94ccc..87951e397c 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -246,9 +246,11 @@ public: if (result.isMember(jss::deposit_authorized)) BEAST_EXPECT(result[jss::deposit_authorized] == authorized); if (authorized) + { BEAST_EXPECT( result.isMember(jss::deposit_authorized) && (result[jss::deposit_authorized] == true)); + } BEAST_EXPECT(result.isMember(jss::error) == !error.empty()); if (!error.empty()) diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index 43c8d788ac..0050429c99 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -347,9 +347,12 @@ class Feature_test : public beast::unit_test::suite (*it).isMember(jss::enabled) && (*it)[jss::enabled].asBool() == expectEnabled, (*it)[jss::name].asString() + " enabled"); if (expectEnabled) + { BEAST_EXPECTS( !(*it).isMember(jss::vetoed), (*it)[jss::name].asString() + " vetoed"); + } else + { BEAST_EXPECTS( (*it).isMember(jss::vetoed) && (*it)[jss::vetoed].isBool() == !expectObsolete && (!(*it)[jss::vetoed].isBool() || @@ -357,6 +360,7 @@ class Feature_test : public beast::unit_test::suite ((*it)[jss::vetoed].isBool() || (*it)[jss::vetoed].asString() == "Obsolete"), (*it)[jss::name].asString() + " vetoed"); + } BEAST_EXPECTS( (*it).isMember(jss::supported) && (*it)[jss::supported].asBool() == expectSupported, (*it)[jss::name].asString() + " supported"); diff --git a/src/test/rpc/KeyGeneration_test.cpp b/src/test/rpc/KeyGeneration_test.cpp index dc46a66c07..e4af2608b7 100644 --- a/src/test/rpc/KeyGeneration_test.cpp +++ b/src/test/rpc/KeyGeneration_test.cpp @@ -164,9 +164,13 @@ public: auto const wallet = testSecretWallet(params, strings); if (value == strings.passphrase) + { BEAST_EXPECT(wallet[jss::warning] == strings.passphrase_warning); + } else + { BEAST_EXPECT(!wallet.isMember(jss::warning)); + } } void diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 1cce3d1383..472f5b2aa2 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -13,7 +13,7 @@ public: checkMarker(Json::Value const& val) { return val.isMember(jss::marker) && val[jss::marker].isString() && - val[jss::marker].asString().size() > 0; + !val[jss::marker].asString().empty(); } void @@ -198,8 +198,10 @@ public: jvParams[jss::ledger_index] = "closed"; auto jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result]; if (BEAST_EXPECT(jrr.isMember(jss::ledger))) + { BEAST_EXPECT( jrr[jss::ledger][jss::ledger_hash] == to_string(env.closed()->header().hash)); + } } { // Closed ledger with binary form diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index ffc4329109..eec114b71c 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -60,10 +60,8 @@ getFieldType(Json::StaticString fieldName) { return it->second; } - else - { - Throw("`mappings` is missing field " + std::string(fieldName.c_str())); - } + + Throw("`mappings` is missing field " + std::string(fieldName.c_str())); } std::string @@ -110,10 +108,12 @@ class LedgerEntry_test : public beast::unit_test::suite if (BEAST_EXPECT(jv.isMember(jss::status))) BEAST_EXPECTS(jv[jss::status] == "error", std::to_string(location.line())); if (BEAST_EXPECT(jv.isMember(jss::error))) + { BEAST_EXPECTS( jv[jss::error] == err, "Expected error " + err + ", received " + jv[jss::error].asString() + ", at line " + std::to_string(location.line()) + ", " + jv.toStyledString()); + } if (msg.empty()) { BEAST_EXPECTS( @@ -122,11 +122,13 @@ class LedgerEntry_test : public beast::unit_test::suite "\", at line " + std::to_string(location.line()) + ", " + jv.toStyledString()); } else if (BEAST_EXPECT(jv.isMember(jss::error_message))) + { BEAST_EXPECTS( jv[jss::error_message] == msg, "Expected error message \"" + msg + "\", received \"" + jv[jss::error_message].asString() + "\", at line " + std::to_string(location.line()) + ", " + jv.toStyledString()); + } } std::vector @@ -175,7 +177,7 @@ class LedgerEntry_test : public beast::unit_test::suite values.reserve(allBadValues.size() - indexSet.size()); for (std::size_t i = 0; i < allBadValues.size(); ++i) { - if (indexSet.find(i) == indexSet.end()) + if (!indexSet.contains(i)) { values.push_back(allBadValues[i]); } @@ -286,10 +288,14 @@ class LedgerEntry_test : public beast::unit_test::suite Json::Value const jrr = env.rpc( apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result]; if (apiVersion < 2u) + { checkErrorValue(jrr, "unknownOption", "", location); + } else + { checkErrorValue( jrr, "invalidParams", "No ledger_entry params provided.", location); + } } auto tryField = [&](Json::Value fieldValue) -> void { correctRequest[fieldName] = fieldValue; @@ -491,9 +497,13 @@ class LedgerEntry_test : public beast::unit_test::suite env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result]; if (apiVersion < 2u) + { checkErrorValue(jrr, "unknownOption", ""); + } else + { checkErrorValue(jrr, "invalidParams", "No ledger_entry params provided."); + } } }); } @@ -2640,7 +2650,9 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, BEAST_EXPECT(jv[jss::error_message] == Json::nullValue || jv[jss::error_message] == ""); } else if (BEAST_EXPECT(jv.isMember(jss::error_message))) + { BEAST_EXPECT(jv[jss::error_message] == msg); + } } void diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index d45f50c657..2f4a63a090 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -30,10 +30,12 @@ class LedgerRPC_test : public beast::unit_test::suite BEAST_EXPECT(jv[jss::error_message] == Json::nullValue || jv[jss::error_message] == ""); } else if (BEAST_EXPECT(jv.isMember(jss::error_message))) + { BEAST_EXPECTS( jv[jss::error_message] == msg, "Expected error message \"" + msg + "\", received \"" + jv[jss::error_message].asString() + "\""); + } } // Corrupt a valid address by replacing the 10th character with '!'. @@ -634,15 +636,19 @@ class LedgerRPC_test : public beast::unit_test::suite BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray()); for (auto i = 0; i < jrr[jss::ledger][jss::accountState].size(); i++) + { if (jrr[jss::ledger][jss::accountState][i]["LedgerEntryType"] == jss::LedgerHashes) { index = jrr[jss::ledger][jss::accountState][i]["index"].asString(); hashesLedgerEntryIndex = i; } + } for (auto const& object : jrr[jss::ledger][jss::accountState]) + { if (object["LedgerEntryType"] == jss::LedgerHashes) index = object["index"].asString(); + } // jss::type is a deprecated field BEAST_EXPECT( diff --git a/src/test/rpc/NoRippleCheck_test.cpp b/src/test/rpc/NoRippleCheck_test.cpp index c436c1d7b1..54a2931ba5 100644 --- a/src/test/rpc/NoRippleCheck_test.cpp +++ b/src/test/rpc/NoRippleCheck_test.cpp @@ -235,8 +235,10 @@ public: { testBadInput(); for (auto user : {true, false}) + { for (auto problem : {true, false}) testBasic(user, problem); + } } }; diff --git a/src/test/rpc/NoRipple_test.cpp b/src/test/rpc/NoRipple_test.cpp index 27f13aa3e2..fcf412bbd4 100644 --- a/src/test/rpc/NoRipple_test.cpp +++ b/src/test/rpc/NoRipple_test.cpp @@ -234,9 +234,13 @@ public: auto lines = env.rpc("json", "noripple_check", to_string(params)); if (apiVersion < 2u) + { BEAST_EXPECT(lines[jss::result][jss::status] == "success"); + } else + { BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams"); + } } } } diff --git a/src/test/rpc/RPCOverload_test.cpp b/src/test/rpc/RPCOverload_test.cpp index c8f02cd0a3..e5558af82c 100644 --- a/src/test/rpc/RPCOverload_test.cpp +++ b/src/test/rpc/RPCOverload_test.cpp @@ -45,7 +45,9 @@ public: jv = jv[jss::result]; // When booted, we just get a null json response if (jv.isNull()) + { booted = true; + } else if (!(jv.isMember(jss::status) && (jv[jss::status] == "success"))) { // Don't use BEAST_EXPECT above b/c it will be called a diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index 9fdfe5e13b..5bb2c31757 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -85,7 +85,7 @@ admin = 127.0.0.1 (git[jss::hash].isString() && git[jss::hash].asString().size() == 40)); BEAST_EXPECT( !git.isMember(jss::branch) || - (git[jss::branch].isString() && git[jss::branch].asString().size() != 0)); + (git[jss::branch].isString() && !git[jss::branch].asString().empty())); } } diff --git a/src/test/rpc/Simulate_test.cpp b/src/test/rpc/Simulate_test.cpp index 6712c3f229..74f9b03111 100644 --- a/src/test/rpc/Simulate_test.cpp +++ b/src/test/rpc/Simulate_test.cpp @@ -59,7 +59,7 @@ class Simulate_test : public beast::unit_test::suite int const expectedSequence, XRPAmount const& expectedFee) { - return checkBasicReturnValidity( + checkBasicReturnValidity( result, tx, expectedSequence, expectedFee.jsonClipped().asString()); } diff --git a/src/test/rpc/Transaction_test.cpp b/src/test/rpc/Transaction_test.cpp index fa76f62cdf..2709900bf1 100644 --- a/src/test/rpc/Transaction_test.cpp +++ b/src/test/rpc/Transaction_test.cpp @@ -92,9 +92,13 @@ class Transaction_test : public beast::unit_test::suite result[jss::result][jss::error] == NOT_FOUND); if (deltaEndSeq) + { BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); + } else + { BEAST_EXPECT(result[jss::result][jss::searched_all].asBool()); + } } // Find transactions outside of provided range. @@ -329,9 +333,13 @@ class Transaction_test : public beast::unit_test::suite result[jss::result][jss::error] == NOT_FOUND); if (deltaEndSeq) + { BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); + } else + { BEAST_EXPECT(!result[jss::result][jss::searched_all].asBool()); + } } // Find transactions outside of provided range. diff --git a/src/test/rpc/ValidatorRPC_test.cpp b/src/test/rpc/ValidatorRPC_test.cpp index 829e2699a7..43ba188f6a 100644 --- a/src/test/rpc/ValidatorRPC_test.cpp +++ b/src/test/rpc/ValidatorRPC_test.cpp @@ -134,7 +134,7 @@ public: parseBase58(TokenType::NodePublic, jrrnUnl[x].asString()); BEAST_EXPECT(parsedKey); if (parsedKey) - BEAST_EXPECT(disabledKeys.find(*parsedKey) != disabledKeys.end()); + BEAST_EXPECT(disabledKeys.contains(*parsedKey)); } disabledKeys.clear(); diff --git a/src/test/rpc/Version_test.cpp b/src/test/rpc/Version_test.cpp index c86bb8a660..7fa6720f83 100644 --- a/src/test/rpc/Version_test.cpp +++ b/src/test/rpc/Version_test.cpp @@ -42,10 +42,12 @@ class Version_test : public beast::unit_test::suite auto badVersion = [](Json::Value const& re) -> bool { if (re.isMember("error_what")) + { if (re["error_what"].isString()) { return re["error_what"].asString().find(jss::invalid_API_version.c_str()) == 0; } + } return false; }; diff --git a/src/test/server/ServerStatus_test.cpp b/src/test/server/ServerStatus_test.cpp index 49ee3d2079..178b85b3e4 100644 --- a/src/test/server/ServerStatus_test.cpp +++ b/src/test/server/ServerStatus_test.cpp @@ -616,9 +616,8 @@ class ServerStatus_test : public beast::unit_test::suite, public beast::test::en boost::system::error_code ec; doRequest(yield, makeWSUpgrade(ip, port), ip, port, true, resp, ec); BEAST_EXPECT(resp.result() == boost::beast::http::status::switching_protocols); - BEAST_EXPECT(resp.find("Upgrade") != resp.end() && resp["Upgrade"] == "websocket"); - BEAST_EXPECT( - resp.find("Connection") != resp.end() && boost::iequals(resp["Connection"], "upgrade")); + BEAST_EXPECT(resp.contains("Upgrade") && resp["Upgrade"] == "websocket"); + BEAST_EXPECT(resp.contains("Connection") && boost::iequals(resp["Connection"], "upgrade")); } void diff --git a/src/test/server/Server_test.cpp b/src/test/server/Server_test.cpp index bc12d98659..bce8bced60 100644 --- a/src/test/server/Server_test.cpp +++ b/src/test/server/Server_test.cpp @@ -121,9 +121,13 @@ public: { session.write(std::string("Hello, world!\n")); if (beast::rfc2616::is_keep_alive(session.request())) + { session.complete(); + } else + { session.close(true); + } } void diff --git a/src/test/shamap/SHAMapSync_test.cpp b/src/test/shamap/SHAMapSync_test.cpp index 81305c4dab..a8f3a478b2 100644 --- a/src/test/shamap/SHAMapSync_test.cpp +++ b/src/test/shamap/SHAMapSync_test.cpp @@ -107,7 +107,7 @@ public: BEAST_EXPECT(source.getNodeFat(SHAMapNodeID(), a, rand_bool(eng_), rand_int(eng_, 2))); - unexpected(a.size() < 1, "NodeSize"); + unexpected(a.empty(), "NodeSize"); BEAST_EXPECT(destination.addRootNode(source.getHash(), makeSlice(a[0].second), nullptr) .isGood()); diff --git a/src/test/shamap/SHAMap_test.cpp b/src/test/shamap/SHAMap_test.cpp index 1eb050178c..b16f7b157f 100644 --- a/src/test/shamap/SHAMap_test.cpp +++ b/src/test/shamap/SHAMap_test.cpp @@ -110,9 +110,13 @@ public: run(bool backed, beast::Journal const& journal) { if (backed) + { testcase("add/traverse backed"); + } else + { testcase("add/traverse unbacked"); + } tests::TestNodeFamily f(journal); @@ -163,9 +167,13 @@ public: unexpected(i != e, "bad traverse"); if (backed) + { testcase("snapshot backed"); + } else + { testcase("snapshot unbacked"); + } SHAMapHash mapHash = sMap.getHash(); std::shared_ptr map2 = sMap.snapShot(false); @@ -191,9 +199,13 @@ public: sMap.dump(); if (backed) + { testcase("build/tear backed"); + } else + { testcase("build/tear unbacked"); + } { constexpr std::array keys{ uint256( @@ -269,9 +281,13 @@ public: } if (backed) + { testcase("iterate backed"); + } else + { testcase("iterate unbacked"); + } { constexpr std::array keys{ diff --git a/src/test/unit_test/multi_runner.cpp b/src/test/unit_test/multi_runner.cpp index 3838f128f0..239564bd7c 100644 --- a/src/test/unit_test/multi_runner.cpp +++ b/src/test/unit_test/multi_runner.cpp @@ -108,7 +108,7 @@ results::print(S& s) { using namespace beast::unit_test; - if (top.size() > 0) + if (!top.empty()) { s << "Longest suite times:\n"; for (auto const& [name, dur] : top) @@ -234,9 +234,13 @@ multi_runner_base::multi_runner_base() region_ = boost::interprocess::mapped_region{shared_mem_, boost::interprocess::read_write}; if (IsParent) + { inner_ = new (region_.get_address()) inner{}; + } else + { inner_ = reinterpret_cast(region_.get_address()); + } } catch (...) { diff --git a/src/tests/libxrpl/basics/Slice.cpp b/src/tests/libxrpl/basics/Slice.cpp index 0e5e0877d0..72f2d081c7 100644 --- a/src/tests/libxrpl/basics/Slice.cpp +++ b/src/tests/libxrpl/basics/Slice.cpp @@ -28,18 +28,26 @@ TEST(Slice, equality_and_inequality) EXPECT_NE(s1.data(), nullptr); if (i == 0) + { EXPECT_EQ(s1, s0); + } else + { EXPECT_NE(s1, s0); + } for (std::size_t j = 0; j != sizeof(data); ++j) { Slice const s2{data, j}; if (i == j) + { EXPECT_EQ(s1, s2); + } else + { EXPECT_NE(s1, s2); + } } } diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 16cf7f4c9d..5a3d53dae0 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -498,7 +498,7 @@ RCLConsensus::Adaptor::doAccept( std::move(accepted), [curr = built.seq(), j = app_.journal("CensorshipDetector"), &failed]( uint256 const& id, LedgerIndex seq) { - if (failed.count(id)) + if (failed.contains(id)) return true; auto const wait = curr - seq; @@ -585,9 +585,13 @@ RCLConsensus::Adaptor::doAccept( auto const lastVal = ledgerMaster_.getValidatedLedger(); std::optional rules; if (lastVal) + { rules = makeRulesGivenLedger(*lastVal, app_.config().features); + } else + { rules.emplace(app_.config().features); + } app_.openLedger().accept( app_, *rules, @@ -664,9 +668,13 @@ RCLConsensus::Adaptor::notify( protocol::TMStatusChange s; if (!haveCorrectLCL) + { s.set_newevent(protocol::neLOST_SYNC); + } else + { s.set_newevent(ne); + } s.set_ledgerseq(ledger.seq()); s.set_networktime(app_.timeKeeper().now().time_since_epoch().count()); @@ -726,9 +734,13 @@ RCLConsensus::Adaptor::buildLCL( // And stash the ledger in the ledger master if (ledgerMaster_.storeLedger(built)) + { JLOG(j_.debug()) << "Consensus built ledger we already had"; + } else if (app_.getInboundLedgers().find(built->header().hash)) + { JLOG(j_.debug()) << "Consensus built ledger we were acquiring"; + } else JLOG(j_.debug()) << "Consensus built new ledger"; return RCLCxLedger{std::move(built)}; diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.cpp b/src/xrpld/app/consensus/RCLCxPeerPos.cpp index 4128d65c49..cdb8350468 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.cpp +++ b/src/xrpld/app/consensus/RCLCxPeerPos.cpp @@ -19,7 +19,7 @@ RCLCxPeerPos::RCLCxPeerPos( signature.size() != 0 && signature.size() <= signature_.capacity(), "xrpl::RCLCxPeerPos::RCLCxPeerPos : valid signature size"); - if (signature.size() != 0 && signature.size() <= signature_.capacity()) + if (!signature.empty() && signature.size() <= signature_.capacity()) signature_.assign(signature.begin(), signature.end()); } diff --git a/src/xrpld/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp index 60e02f53b4..a968acb1a7 100644 --- a/src/xrpld/app/consensus/RCLValidations.cpp +++ b/src/xrpld/app/consensus/RCLValidations.cpp @@ -205,14 +205,18 @@ handleNewValidation( }(); if (outcome == ValStatus::conflicting) + { ls << "Byzantine Behavior Detector: " << (val->isTrusted() ? "trusted " : "untrusted ") << id << ": Conflicting validation for " << seq << "!\n[" << val->getSerializer().slice() << "]"; + } if (outcome == ValStatus::multiple) + { ls << "Byzantine Behavior Detector: " << (val->isTrusted() ? "trusted " : "untrusted ") << id << ": Multiple validations for " << seq << "/" << hash << "!\n[" << val->getSerializer().slice() << "]"; + } } } diff --git a/src/xrpld/app/ledger/AcceptedLedger.cpp b/src/xrpld/app/ledger/AcceptedLedger.cpp index 339c5f57c7..1da70702bf 100644 --- a/src/xrpld/app/ledger/AcceptedLedger.cpp +++ b/src/xrpld/app/ledger/AcceptedLedger.cpp @@ -10,8 +10,10 @@ AcceptedLedger::AcceptedLedger(std::shared_ptr const& ledger) : auto insertAll = [&](auto const& txns) { for (auto const& item : txns) + { transactions_.emplace_back( std::make_unique(ledger, item.first, item.second)); + } }; transactions_.reserve(256); diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index 3a81b5f3a3..7be1b5e762 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -597,9 +597,13 @@ Ledger::setup() if (src) { if (src->native()) + { dest = src->xrp(); + } else + { ret = false; + } } }; assign(fees_.base, baseFeeXRP); @@ -608,11 +612,15 @@ Ledger::setup() newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP; } if (oldFees && newFees) + { // Should be all of one or the other, but not both ret = false; + } if (!rules_.enabled(featureXRPFees) && newFees) + { // Can't populate the new fees before the amendment is enabled ret = false; + } } } catch (SHAMapMissingNode const&) @@ -770,9 +778,11 @@ Ledger::walkLedger(beast::Journal j, bool parallel) const else { if (parallel) + { return stateMap_.walkMapParallel(missingNodes1, 32); - else - stateMap_.walkMap(missingNodes1, 32); + } + + stateMap_.walkMap(missingNodes1, 32); } if (!missingNodes1.empty()) @@ -864,9 +874,13 @@ Ledger::updateSkipList() sle->setFieldV256(sfHashes, STVector256(hashes)); sle->setFieldU32(sfLastLedgerSequence, prevIndex); if (created) + { rawInsert(sle); + } else + { rawReplace(sle); + } } // update record of past 256 ledger @@ -891,9 +905,13 @@ Ledger::updateSkipList() sle->setFieldV256(sfHashes, STVector256(hashes)); sle->setFieldU32(sfLastLedgerSequence, prevIndex); if (created) + { rawInsert(sle); + } else + { rawReplace(sle); + } } bool diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index f2e2afb3e6..5ff5555fff 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -337,9 +337,11 @@ LedgerHistory::handleMismatch( if (builtConsensusHash && validatedConsensusHash) { if (builtConsensusHash != validatedConsensusHash) + { JLOG(j_.error()) << "MISMATCH on consensus transaction set " << " built: " << to_string(*builtConsensusHash) << " validated: " << to_string(*validatedConsensusHash); + } else JLOG(j_.error()) << "MISMATCH with same consensus transaction set: " << to_string(*builtConsensusHash); @@ -350,7 +352,9 @@ LedgerHistory::handleMismatch( auto const validTx = leaves(validLedger->txMap()); if (builtTx == validTx) + { JLOG(j_.error()) << "MISMATCH with same " << builtTx.size() << " transactions"; + } else JLOG(j_.error()) << "MISMATCH with " << builtTx.size() << " built and " << validTx.size() << " valid transactions."; diff --git a/src/xrpld/app/ledger/OrderBookDBImpl.cpp b/src/xrpld/app/ledger/OrderBookDBImpl.cpp index b82fa3896b..2691935911 100644 --- a/src/xrpld/app/ledger/OrderBookDBImpl.cpp +++ b/src/xrpld/app/ledger/OrderBookDBImpl.cpp @@ -52,12 +52,16 @@ OrderBookDBImpl::setup(std::shared_ptr const& ledger) if (pathSearchMax_ != 0) { if (standalone_) + { update(ledger); + } else + { registry_.getJobQueue().addJob( jtUPDATE_PF, "OrderBookUpd" + std::to_string(ledger->seq()), [this, ledger]() { update(ledger); }); + } } } @@ -111,14 +115,22 @@ OrderBookDBImpl::update(std::shared_ptr const& ledger) book.domain = (*sle)[~sfDomainID]; if (book.domain) + { domainBooks[{book.in, *book.domain}].insert(book.out); + } else + { allBooks[book.in].insert(book.out); + } if (book.domain && isXRP(book.out)) + { xrpDomainBooks.insert({book.in, *book.domain}); + } else if (isXRP(book.out)) + { xrpBooks.insert(book.in); + } ++cnt; } @@ -167,14 +179,22 @@ OrderBookDBImpl::addOrderBook(Book const& book) std::lock_guard sl(mLock); if (book.domain) + { domainBooks_[{book.in, *book.domain}].insert(book.out); + } else + { allBooks_[book.in].insert(book.out); + } if (book.domain && toXRP) + { xrpDomainBooks_.insert({book.in, *book.domain}); + } else if (toXRP) + { xrpBooks_.insert(book.in); + } } // return list of all orderbooks that want this issuerID and currencyID @@ -198,9 +218,13 @@ OrderBookDBImpl::getBooksByTakerPays(Issue const& issue, std::optional }; if (!domain) + { getBooks(allBooks_, issue); + } else + { getBooks(domainBooks_, std::make_pair(issue, *domain)); + } } return ret; @@ -306,11 +330,17 @@ OrderBookDBImpl::processTxn( // We need a field that contains the TakerGets and TakerPays // parameters. if (node.getFName() == sfModifiedNode) + { process(sfPreviousFields); + } else if (node.getFName() == sfCreatedNode) + { process(sfNewFields); + } else if (node.getFName() == sfDeletedNode) + { process(sfFinalFields); + } } } catch (std::exception const& ex) diff --git a/src/xrpld/app/ledger/detail/BuildLedger.cpp b/src/xrpld/app/ledger/detail/BuildLedger.cpp index c4f8f9e60a..5ad72c7a69 100644 --- a/src/xrpld/app/ledger/detail/BuildLedger.cpp +++ b/src/xrpld/app/ledger/detail/BuildLedger.cpp @@ -181,10 +181,12 @@ buildLedger( auto const applied = applyTransactions(app, built, txns, failedTxns, accum, j); if (!txns.empty() || !failedTxns.empty()) + { JLOG(j.debug()) << "Applied " << applied << " transactions; " << failedTxns.size() << " failed and " << txns.size() << " will be retried. " << "Total transactions in ledger (including Inner Batch): " << accum.txCount(); + } else JLOG(j.debug()) << "Applied " << applied << " transactions. " << "Total transactions in ledger (including Inner Batch): " diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index b8158e507f..9f7312ea34 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -145,9 +145,13 @@ InboundLedger::checkLocal() if (!isDone()) { if (mLedger) + { tryDB(mLedger->stateMap().family().db()); + } else + { tryDB(app_.getNodeFamily().db()); + } if (failed_ || complete_) { done(); @@ -184,7 +188,9 @@ neededHashes(uint256 const& root, SHAMap& map, int max, SHAMapSyncFilter* filter if (!root.isZero()) { if (map.getHash().isZero()) + { ret.push_back(root); + } else { auto mn = map.getMissingNodes(max, filter); @@ -435,7 +441,9 @@ InboundLedger::done() self->app_.getLedgerMaster().tryAdvance(); } else + { self->app_.getInboundLedgers().logFailure(self->hash_, self->mSeq); + } }); } @@ -461,9 +469,13 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) ss << " from " << peer; if (complete_ || failed_) + { ss << " complete=" << complete_ << " failed=" << failed_; + } else + { ss << " header=" << mHaveHeader << " tx=" << mHaveTransactions << " as=" << mHaveState; + } stream << ss.str(); } @@ -562,7 +574,9 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) tmGL.set_querydepth(2); } else + { tmGL.set_querydepth(1); + } // Get the state data first because it's the most likely to be useful // if we wind up abandoning this fetch. @@ -602,7 +616,9 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (nodes.empty()) { if (!mLedger->stateMap().isValid()) + { failed_ = true; + } else { mHaveState = true; @@ -628,10 +644,8 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) mPeerSet->sendRequest(tmGL, peer); return; } - else - { - JLOG(journal_.trace()) << "All AS nodes filtered"; - } + + JLOG(journal_.trace()) << "All AS nodes filtered"; } } } @@ -667,7 +681,9 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (nodes.empty()) { if (!mLedger->txMap().isValid()) + { failed_ = true; + } else { mHaveTransactions = true; @@ -692,10 +708,8 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) mPeerSet->sendRequest(tmGL, peer); return; } - else - { - JLOG(journal_.trace()) << "All TX nodes filtered"; - } + + JLOG(journal_.trace()) << "All TX nodes filtered"; } } } @@ -823,11 +837,13 @@ InboundLedger::receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode& san) auto [map, rootHash, filter] = [&]() -> std::tuple> { if (packet.type() == protocol::liTX_NODE) + { return { mLedger->txMap(), SHAMapHash{mLedger->header().txHash}, std::make_unique( mLedger->txMap().family().db(), app_.getLedgerMaster())}; + } return { mLedger->stateMap(), SHAMapHash{mLedger->header().accountHash}, @@ -872,9 +888,13 @@ InboundLedger::receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode& san) if (!map.isSynching()) { if (packet.type() == protocol::liTX_NODE) + { mHaveTransactions = true; + } else + { mHaveState = true; + } if (mHaveTransactions && mHaveState) { @@ -1129,9 +1149,13 @@ struct PeerDataCounts while (i != counts.end()) { if (i->second < thresh) + { i = counts.erase(i); + } else + { ++i; + } } } diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index a5fdd889ec..be7577a2c3 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -174,8 +174,10 @@ public: // Stash the data for later processing and see if we need to // dispatch if (ledger->gotData(std::weak_ptr(peer), packet)) + { app_.getJobQueue().addJob( jtLEDGER_DATA, "ProcessLData", [ledger]() { ledger->runData(); }); + } return true; } @@ -290,9 +292,13 @@ public: for (auto const& it : mRecentFailures) { if (it.second > 1) + { ret[std::to_string(it.second)][jss::failed] = true; + } else + { ret[to_string(it.first)][jss::failed] = true; + } } } @@ -301,9 +307,13 @@ public: // getJson is expensive, so call without the lock std::uint32_t seq = it.second->getSeq(); if (seq > 1) + { ret[std::to_string(seq)] = it.second->getJson(0); + } else + { ret[to_string(it.first)] = it.second->getJson(0); + } } return ret; diff --git a/src/xrpld/app/ledger/detail/InboundTransactions.cpp b/src/xrpld/app/ledger/detail/InboundTransactions.cpp index b10adad438..f27f2c33f0 100644 --- a/src/xrpld/app/ledger/detail/InboundTransactions.cpp +++ b/src/xrpld/app/ledger/detail/InboundTransactions.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -167,13 +168,16 @@ public: auto& inboundSet = m_map[hash]; - if (inboundSet.mSeq < m_seq) - inboundSet.mSeq = m_seq; + inboundSet.mSeq = std::max(inboundSet.mSeq, m_seq); if (inboundSet.mSet) + { isNew = false; + } else + { inboundSet.mSet = set; + } inboundSet.mAcquire.reset(); } @@ -202,9 +206,13 @@ public: while (it != m_map.end()) { if (it->second.mSeq < minSeq || it->second.mSeq > maxSeq) + { it = m_map.erase(it); + } else + { ++it; + } } } } diff --git a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp index 4266185591..3052f787dc 100644 --- a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp +++ b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp @@ -93,7 +93,9 @@ public: std::lock_guard lock(mutex_); if (maxRange_ == 0) + { map["status"] = "idle"; + } else { map["status"] = "running"; diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp index e22351fc77..cb2e2e57ea 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp @@ -145,7 +145,7 @@ LedgerDeltaAcquire::addDataCallback(InboundLedger::Reason reason, OnDeltaDataCB& { ScopedLockType sl(mtx_); dataReadyCallbacks_.emplace_back(std::move(cb)); - if (reasons_.count(reason) == 0) + if (!reasons_.contains(reason)) { reasons_.emplace(reason); if (fullLedger_) @@ -185,14 +185,12 @@ LedgerDeltaAcquire::tryBuild(std::shared_ptr const& parent) onLedgerBuilt(sl); return fullLedger_; } - else - { - failed_ = true; - complete_ = false; - JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent " - << parent->header().hash; - Throw("Cannot replay ledger"); - } + + failed_ = true; + complete_ = false; + JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent " + << parent->header().hash; + Throw("Cannot replay ledger"); } void diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index 178e14f5c1..42d7f2ec6e 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -283,7 +283,9 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) app_.getOPs().setAmendmentWarned(); } else + { app_.getOPs().clearAmendmentWarned(); + } } } } @@ -350,10 +352,12 @@ LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) LedgerIndex maxSeq = validLedger->header().seq + 10; if (closeTime > validLedger->header().parentCloseTime) + { maxSeq += std::chrono::duration_cast( closeTime - validLedger->header().parentCloseTime) .count() / 2; + } if (ledger->header().seq > maxSeq) { @@ -520,9 +524,13 @@ LedgerMaster::getFullValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal } if (maybeMin == std::nullopt) + { minVal = maxVal; + } else + { minVal = 1 + *maybeMin; + } return true; } @@ -544,9 +552,9 @@ LedgerMaster::getValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal) // Ensure we shrink the tips as much as possible. If we have 7-9 and // 8,9 are invalid, we don't want to see the 8 and shrink to just 9 // because then we'll have nothing when we could have 7. - while (pendingSaves.count(maxVal) > 0) + while (pendingSaves.contains(maxVal)) --maxVal; - while (pendingSaves.count(minVal) > 0) + while (pendingSaves.contains(minVal)) ++minVal; // Best effort for remaining exclusions @@ -555,9 +563,13 @@ LedgerMaster::getValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal) if ((v.first >= minVal) && (v.first <= maxVal)) { if (v.first > ((minVal + maxVal) / 2)) + { maxVal = v.first - 1; + } else + { minVal = v.first + 1; + } } } @@ -577,9 +589,13 @@ LedgerMaster::getEarliestFetch() std::uint32_t e = getClosedLedger()->header().seq; if (e > fetch_depth_) + { e -= fetch_depth_; + } else + { e = 0; + } return e; } @@ -1094,6 +1110,7 @@ LedgerMaster::consensusBuilt( // Of the ledgers with sufficient validations, // find the one with the highest sequence for (auto& v : count) + { if (v.second.valCount_ > neededValidations) { // If we still don't know the sequence, get it @@ -1109,6 +1126,7 @@ LedgerMaster::consensusBuilt( maxLedger = v.first; } } + } if (maxSeq > mValidLedgerSeq) { @@ -1221,8 +1239,10 @@ LedgerMaster::findNewLedgersToPublish(std::unique_lock& sl { // Can we try to acquire the ledger we need? if (!ledger && (++acqCount < ledger_fetch_size_)) + { ledger = app_.getInboundLedgers().acquire( *hash, seq, InboundLedger::Reason::GENERIC); + } } // Did we acquire the next ledger we need to publish? @@ -1850,7 +1870,9 @@ LedgerMaster::doAdvance(std::unique_lock& sl) JLOG(m_journal.trace()) << "advanceThread should acquire"; } else + { missing = std::nullopt; + } } if (missing) { @@ -2133,9 +2155,11 @@ LedgerMaster::txnIdFromIndex(uint32_t ledgerSeq, uint32_t txnIndex) return {}; for (auto it = lgr->txs.begin(); it != lgr->txs.end(); ++it) + { if (it->first && it->second && it->second->isFieldPresent(sfTransactionIndex) && it->second->getFieldU32(sfTransactionIndex) == txnIndex) return it->first->getTransactionID(); + } return {}; } diff --git a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp index 8f225335c7..b878c840dd 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp @@ -183,7 +183,9 @@ LedgerReplayTask::tryAdvance(ScopedLockType& sl) parent_ = l; } else + { return; + } } complete_ = true; @@ -248,9 +250,13 @@ LedgerReplayTask::addDelta(std::shared_ptr const& delta) if (auto sptr = wptr.lock(); sptr) { if (!good) + { sptr->cancel(); + } else + { sptr->deltaReady(hash); + } } }); diff --git a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp index 5aacf5b5a6..553ff91174 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp @@ -217,7 +217,9 @@ LedgerReplayer::sweep() it = subTasks.erase(it); } else + { ++it; + } } }; removeCannotLocked(skipLists_); diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 038a5ae742..c0211059a1 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -74,7 +74,9 @@ void fillJsonBinary(Json::Value& json, bool closed, LedgerHeader const& info) { if (!closed) + { json[jss::closed] = false; + } else { json[jss::closed] = true; @@ -120,11 +122,13 @@ fillJsonTx( // If applicable, insert delivered amount if (txnType == ttPAYMENT || txnType == ttCHECK_CASH) + { RPC::insertDeliveredAmount( txJson[jss::meta], fill.ledger, txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + } // If applicable, insert mpt issuance id RPC::insertMPTokenIssuanceID( @@ -154,11 +158,13 @@ fillJsonTx( // If applicable, insert delivered amount if (txnType == ttPAYMENT || txnType == ttCHECK_CASH) + { RPC::insertDeliveredAmount( txJson[jss::metaData], fill.ledger, txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + } // If applicable, insert mpt issuance id RPC::insertMPTokenIssuanceID( @@ -233,9 +239,13 @@ fillJsonState(Json::Value& json, LedgerFill const& fill) obj[jss::tx_blob] = serializeHex(*sle); } else if (expanded) + { array.append(sle->getJson(JsonOptions::none)); + } else + { array.append(to_string(sle->key())); + } } } @@ -266,9 +276,13 @@ fillJsonQueue(Json::Value& json, LedgerFill const& fill) auto&& temp = fillJsonTx(fill, bBinary, bExpanded, tx.txn, nullptr); if (fill.context->apiVersion > 1) + { copyFrom(txJson, temp); + } else + { copyFrom(txJson[jss::tx], temp); + } } } @@ -279,14 +293,18 @@ fillJson(Json::Value& json, LedgerFill const& fill) // Is there a way to report this back? auto bFull = isFull(fill); if (isBinary(fill)) + { fillJsonBinary(json, !fill.ledger.open(), fill.ledger.header()); + } else + { fillJson( json, !fill.ledger.open(), fill.ledger.header(), bFull, (fill.context ? fill.context->apiVersion : RPC::apiMaximumSupportedVersion)); + } if (bFull || fill.options & LedgerFill::dumpTxrp) fillJsonTx(json, fill); @@ -318,8 +336,10 @@ getJson(LedgerFill const& fill) void copyFrom(Json::Value& to, Json::Value const& from) { - if (!to) // Short circuit this very common case. + if (!to) + { // Short circuit this very common case. to = from; + } else { // TODO: figure out if there is a way to remove this clause diff --git a/src/xrpld/app/ledger/detail/LocalTxs.cpp b/src/xrpld/app/ledger/detail/LocalTxs.cpp index 48bd80fbf2..8eb821a6c9 100644 --- a/src/xrpld/app/ledger/detail/LocalTxs.cpp +++ b/src/xrpld/app/ledger/detail/LocalTxs.cpp @@ -142,10 +142,12 @@ public: return acctSeq > seqProx; // Remove tefPAST_SEQ if (seqProx.isTicket() && acctSeq.value() <= seqProx.value()) + { // Keep ticket from the future. Note, however, that the // transaction will not be held indefinitely since LocalTxs // will only hold a transaction for a maximum of 5 ledgers. return false; + } // Ticket should have been created by now. Remove if ticket // does not exist. diff --git a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp index 8cc26b1da6..18c5066064 100644 --- a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp +++ b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp @@ -6,6 +6,7 @@ #include +#include #include namespace xrpl { @@ -129,9 +130,13 @@ TransactionAcquire::trigger(std::shared_ptr const& peer) if (nodes.empty()) { if (mMap->isValid()) + { complete_ = true; + } else + { failed_ = true; + } done(); return; @@ -183,13 +188,17 @@ TransactionAcquire::takeNodes( if (d.first.isRoot()) { if (mHaveRoot) + { JLOG(journal_.debug()) << "Got root TXS node, already have it"; + } else if (!mMap->addRootNode(SHAMapHash{hash_}, d.second, nullptr).isGood()) { JLOG(journal_.warn()) << "TX acquire got bad root node"; } else + { mHaveRoot = true; + } } else if (!mMap->addKnownNode(d.first, d.second, &sf).isGood()) { @@ -234,8 +243,7 @@ TransactionAcquire::stillNeed() { ScopedLockType sl(mtx_); - if (timeouts_ > NORM_TIMEOUTS) - timeouts_ = NORM_TIMEOUTS; + timeouts_ = std::min(timeouts_, NORM_TIMEOUTS); failed_ = false; } diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index 53eada2dec..048ef0d9b4 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -92,7 +92,7 @@ private: beast::Journal journal, std::chrono::milliseconds interval, boost::asio::io_context& ios) - : m_event(ev), m_journal(journal), m_probe(interval, ios), lastSample_{} + : m_event(ev), m_journal(journal), m_probe(interval, ios) { } @@ -278,11 +278,17 @@ public: // for the job queue if the server is configured as // "large" or "huge" if there are enough cores. if (config->NODE_SIZE >= 4 && count >= 16) + { count = 6 + std::min(count, 8); + } else if (config->NODE_SIZE >= 3 && count >= 8) + { count = 4 + std::min(count, 6); + } else + { count = 2 + std::min(count, 4); + } return count; }(config_), @@ -600,7 +606,7 @@ public: } void - gotTXSet(std::shared_ptr const& set, bool fromAcquire) + gotTXSet(std::shared_ptr const& set, bool fromAcquire) const { if (set) m_networkOPs->mapComplete(set, fromAcquire); @@ -823,7 +829,7 @@ public: } bool - initNodeStore() + initNodeStore() const { if (config_->doImport) { @@ -1573,7 +1579,9 @@ ApplicationImp::signalStop(std::string msg) if (!isTimeToStop.test_and_set(std::memory_order_acquire)) { if (msg.empty()) + { JLOG(m_journal.warn()) << "Server stopping"; + } else JLOG(m_journal.warn()) << "Server stopping: " << msg; diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index 7f4fb57fb7..a9810ae22b 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -205,9 +205,11 @@ Role GRPCServerImpl::CallData::getRole(bool isUnlimited) { if (isUnlimited) + { return Role::IDENTIFIED; - else - return Role::USER; + } + + return Role::USER; } template diff --git a/src/xrpld/app/main/LoadManager.cpp b/src/xrpld/app/main/LoadManager.cpp index 5d2bd9a81e..f0fc4085ac 100644 --- a/src/xrpld/app/main/LoadManager.cpp +++ b/src/xrpld/app/main/LoadManager.cpp @@ -13,7 +13,7 @@ namespace xrpl { LoadManager::LoadManager(Application& app, beast::Journal journal) - : app_(app), journal_(journal), lastHeartbeat_(), armed_(false) + : app_(app), journal_(journal), armed_(false) { } diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 7c440d728c..03f8076ed1 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -69,9 +69,13 @@ adjustDescriptorLimit(int needed, beast::Journal j) { // If the limit is infinite, then we are good. if (rl.rlim_cur == RLIM_INFINITY) + { available = needed; + } else + { available = rl.rlim_cur; + } if (available < needed) { @@ -195,8 +199,10 @@ public: operator()(beast::unit_test::suite_info const& s) { for (auto& sel : selectors_) + { if (sel(s)) return true; + } return false; } @@ -277,8 +283,10 @@ runUnitTests( } for (std::size_t i = 0; i < num_jobs; ++i) + { children.emplace_back( boost::process::v1::exe = exe_name, boost::process::v1::args = args); + } int bad_child_exits = 0; int terminated_child_exits = 0; @@ -305,17 +313,15 @@ runUnitTests( return EXIT_FAILURE; return EXIT_SUCCESS; } - else - { - // child - multi_runner_child runner{num_jobs, quiet, log}; - runner.arg(argument); - auto const anyFailed = runner.run_multi(multi_selector(pattern)); - if (anyFailed) - return EXIT_FAILURE; - return EXIT_SUCCESS; - } + // child + multi_runner_child runner{num_jobs, quiet, log}; + runner.arg(argument); + auto const anyFailed = runner.run_multi(multi_selector(pattern)); + + if (anyFailed) + return EXIT_FAILURE; + return EXIT_SUCCESS; } #endif // ENABLE_TESTS @@ -468,13 +474,13 @@ run(int argc, char** argv) return 1; } - if (vm.count("help")) + if (vm.contains("help")) { printHelp(desc); return 0; } - if (vm.count("version")) + if (vm.contains("version")) { std::cout << "rippled version " << BuildInfo::getVersionString() << std::endl; std::cout << "Git commit hash: " << xrpl::git::getCommitHash() << std::endl; @@ -493,57 +499,53 @@ run(int argc, char** argv) // Run the unit tests if requested. // The unit tests will exit the application with an appropriate return code. // - if (vm.count("unittest")) + if (vm.contains("unittest")) { std::string argument; - if (vm.count("unittest-arg")) + if (vm.contains("unittest-arg")) argument = vm["unittest-arg"].as(); std::size_t numJobs = 1; bool unittestChild = false; - if (vm.count("unittest-jobs")) + if (vm.contains("unittest-jobs")) numJobs = std::max(numJobs, vm["unittest-jobs"].as()); - unittestChild = bool(vm.count("unittest-child")); + unittestChild = vm.contains("unittest-child"); return runUnitTests( vm["unittest"].as(), argument, - bool(vm.count("quiet")), - bool(vm.count("unittest-log")), + vm.contains("quiet"), + vm.contains("unittest-log"), unittestChild, - bool(vm.count("unittest-ipv6")), + vm.contains("unittest-ipv6"), numJobs, argc, argv); } // LCOV_EXCL_START - else + + if (vm.contains("unittest-jobs")) { - if (vm.count("unittest-jobs")) - { - // unittest jobs only makes sense with `unittest` - std::cerr << "rippled: '--unittest-jobs' specified without " - "'--unittest'.\n"; - std::cerr << "To run the unit tests the '--unittest' option must " - "be present.\n"; - return 1; - } + // unittest jobs only makes sense with `unittest` + std::cerr << "rippled: '--unittest-jobs' specified without " + "'--unittest'.\n"; + std::cerr << "To run the unit tests the '--unittest' option must " + "be present.\n"; + return 1; } + #endif // ENABLE_TESTS auto config = std::make_unique(); - auto configFile = vm.count("conf") ? vm["conf"].as() : std::string(); + auto configFile = vm.contains("conf") ? vm["conf"].as() : std::string(); // config file, quiet flag. config->setup( - configFile, - bool(vm.count("quiet")), - bool(vm.count("silent")), - bool(vm.count("standalone"))); + configFile, vm.contains("quiet"), vm.contains("silent"), vm.contains("standalone")); - if (vm.count("vacuum")) + if (vm.contains("vacuum")) { if (config->standalone()) { @@ -609,21 +611,21 @@ run(int argc, char** argv) } } - if (vm.count("start")) + if (vm.contains("start")) { config->START_UP = StartUpType::FRESH; } - if (vm.count("import")) + if (vm.contains("import")) config->doImport = true; - if (vm.count("ledger")) + if (vm.contains("ledger")) { config->START_LEDGER = vm["ledger"].as(); - if (vm.count("replay")) + if (vm.contains("replay")) { config->START_UP = StartUpType::REPLAY; - if (vm.count("trap_tx_hash")) + if (vm.contains("trap_tx_hash")) { uint256 tmp = {}; auto hash = vm["trap_tx_hash"].as(); @@ -641,25 +643,27 @@ run(int argc, char** argv) } } else + { config->START_UP = StartUpType::LOAD; + } } - else if (vm.count("ledgerfile")) + else if (vm.contains("ledgerfile")) { config->START_LEDGER = vm["ledgerfile"].as(); config->START_UP = StartUpType::LOAD_FILE; } - else if (vm.count("load") || config->FAST_LOAD) + else if (vm.contains("load") || config->FAST_LOAD) { config->START_UP = StartUpType::LOAD; } - if (vm.count("trap_tx_hash") && vm.count("replay") == 0) + if (vm.contains("trap_tx_hash") && !vm.contains("replay")) { std::cerr << "Cannot use trap option without replay option" << std::endl; return -1; } - if (vm.count("net") && !config->FAST_LOAD) + if (vm.contains("net") && !config->FAST_LOAD) { if ((config->START_UP == StartUpType::LOAD) || (config->START_UP == StartUpType::REPLAY)) { @@ -670,14 +674,14 @@ run(int argc, char** argv) config->START_UP = StartUpType::NETWORK; } - if (vm.count("valid")) + if (vm.contains("valid")) { config->START_VALID = true; } // Override the RPC destination IP address. This must // happen after the config file is loaded. - if (vm.count("rpc_ip")) + if (vm.contains("rpc_ip")) { auto endpoint = beast::IP::Endpoint::from_string_checked(vm["rpc_ip"].as()); if (!endpoint) @@ -689,7 +693,7 @@ run(int argc, char** argv) if (endpoint->port() == 0) { std::cerr << "No port specified in rpc_ip.\n"; - if (vm.count("rpc_port")) + if (vm.contains("rpc_port")) { std::cerr << "WARNING: using deprecated rpc_port param.\n"; try @@ -705,13 +709,15 @@ run(int argc, char** argv) } } else + { return -1; + } } config->rpc_ip = std::move(*endpoint); } - if (vm.count("quorum")) + if (vm.contains("quorum")) { try { @@ -732,15 +738,19 @@ run(int argc, char** argv) using namespace beast::severities; Severity thresh = kInfo; - if (vm.count("quiet")) + if (vm.contains("quiet")) + { thresh = kFatal; - else if (vm.count("verbose")) + } + else if (vm.contains("verbose")) + { thresh = kTrace; + } auto logs = std::make_unique(thresh); // No arguments. Run server. - if (!vm.count("parameters")) + if (!vm.contains("parameters")) { // TODO: this comment can be removed in a future release - // say 1.7 or higher @@ -760,7 +770,7 @@ run(int argc, char** argv) if (!adjustDescriptorLimit(1024, logs->journal("Application"))) return -1; - if (vm.count("debug")) + if (vm.contains("debug")) setDebugLogSink(logs->makeSink("Debug", beast::severities::kTrace)); auto app = diff --git a/src/xrpld/app/main/NodeIdentity.cpp b/src/xrpld/app/main/NodeIdentity.cpp index 3019caeb31..bc2c943b10 100644 --- a/src/xrpld/app/main/NodeIdentity.cpp +++ b/src/xrpld/app/main/NodeIdentity.cpp @@ -12,7 +12,7 @@ getNodeIdentity(Application& app, boost::program_options::variables_map const& c { std::optional seed; - if (cmdline.count("nodeid")) + if (cmdline.contains("nodeid")) { seed = parseGenericSeed(cmdline["nodeid"].as(), false); @@ -37,7 +37,7 @@ getNodeIdentity(Application& app, boost::program_options::variables_map const& c auto db = app.getWalletDB().checkoutDb(); - if (cmdline.count("newnodeid") != 0) + if (cmdline.contains("newnodeid")) clearNodeIdentity(*db); return getNodeIdentity(*db); diff --git a/src/xrpld/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp index 5cb203115a..764a9564ad 100644 --- a/src/xrpld/app/misc/FeeVoteImpl.cpp +++ b/src/xrpld/app/misc/FeeVoteImpl.cpp @@ -177,9 +177,13 @@ FeeVoteImpl::doVoting( { auto const vote = field->xrp(); if (isLegalAmountSigned(vote)) + { value.addVote(vote); + } else + { value.noVote(); + } } else { @@ -207,12 +211,16 @@ FeeVoteImpl::doVoting( auto const vote = *field; if (vote <= std::numeric_limits::max() && isLegalAmountSigned(XRPAmount{unsafe_cast(vote)})) + { value.addVote(XRPAmount{unsafe_cast(vote)}); + } else + { // Invalid amounts will be treated as if they're // not provided. Don't throw because this value is // provided by an external entity. value.noVote(); + } } else { diff --git a/src/xrpld/app/misc/NegativeUNLVote.cpp b/src/xrpld/app/misc/NegativeUNLVote.cpp index 6673785b61..8f0ba5255a 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.cpp +++ b/src/xrpld/app/misc/NegativeUNLVote.cpp @@ -52,7 +52,7 @@ NegativeUNLVote::doVoting( { auto nid = calcNodeID(k); negUnlNodeIDs.emplace(nid); - if (!nidToKeyMap.count(nid)) + if (!nidToKeyMap.contains(nid)) { nidToKeyMap.emplace(nid, k); } @@ -175,7 +175,7 @@ NegativeUNLVote::buildScoreTable( for (auto const& v : validations.getTrustedForLedger(ledgerAncestors[numAncestors - 1 - i], seq - 2 - i)) { - if (scoreTable.count(v->getNodeID())) + if (scoreTable.contains(v->getNodeID())) ++scoreTable[v->getNodeID()]; } } @@ -195,24 +195,20 @@ NegativeUNLVote::buildScoreTable( << " The reliability measurement could be wrong."; return {}; } - else if ( - myValidationCount > negativeUNLMinLocalValsToVote && + if (myValidationCount > negativeUNLMinLocalValsToVote && myValidationCount <= FLAG_LEDGER_INTERVAL) { return scoreTable; } - else - { - // cannot happen because validations.getTrustedForLedger does not - // return multiple validations of the same ledger from a validator. - JLOG(j_.error()) << "N-UNL: ledger " << seq << ". Local node issued " << myValidationCount - << " validations in last " << FLAG_LEDGER_INTERVAL - << " ledgers. Too many!"; - return {}; - } + + // cannot happen because validations.getTrustedForLedger does not + // return multiple validations of the same ledger from a validator. + JLOG(j_.error()) << "N-UNL: ledger " << seq << ". Local node issued " << myValidationCount + << " validations in last " << FLAG_LEDGER_INTERVAL << " ledgers. Too many!"; + return {}; } -NegativeUNLVote::Candidates const +NegativeUNLVote::Candidates NegativeUNLVote::findAllCandidates( hash_set const& unl, hash_set const& negUnl, @@ -225,7 +221,7 @@ NegativeUNLVote::findAllCandidates( std::size_t negativeListed = 0; for (auto const& n : unl) { - if (negUnl.count(n)) + if (negUnl.contains(n)) ++negativeListed; } bool const result = negativeListed < maxNegativeListed; @@ -246,8 +242,8 @@ NegativeUNLVote::findAllCandidates( // (2) has less than negativeUNLLowWaterMark validations, // (3) is not in negUnl, and // (4) is not a new validator. - if (canAdd && score < negativeUNLLowWaterMark && !negUnl.count(nodeId) && - !newValidators_.count(nodeId)) + if (canAdd && score < negativeUNLLowWaterMark && !negUnl.contains(nodeId) && + !newValidators_.contains(nodeId)) { JLOG(j_.trace()) << "N-UNL: toDisable candidate " << nodeId; candidates.toDisableCandidates.push_back(nodeId); @@ -256,7 +252,7 @@ NegativeUNLVote::findAllCandidates( // Find toReEnable Candidates: check if // (1) has more than negativeUNLHighWaterMark validations, // (2) is in negUnl - if (score > negativeUNLHighWaterMark && negUnl.count(nodeId)) + if (score > negativeUNLHighWaterMark && negUnl.contains(nodeId)) { JLOG(j_.trace()) << "N-UNL: toReEnable candidate " << nodeId; candidates.toReEnableCandidates.push_back(nodeId); @@ -277,7 +273,7 @@ NegativeUNLVote::findAllCandidates( { for (auto const& n : negUnl) { - if (!unl.count(n)) + if (!unl.contains(n)) { candidates.toReEnableCandidates.push_back(n); } @@ -292,7 +288,7 @@ NegativeUNLVote::newValidators(LedgerIndex seq, hash_set const& nowTrust std::lock_guard lock(mutex_); for (auto const& n : nowTrusted) { - if (newValidators_.find(n) == newValidators_.end()) + if (!newValidators_.contains(n)) { JLOG(j_.trace()) << "N-UNL: add a new validator " << n << " at ledger seq=" << seq; newValidators_[n] = seq; diff --git a/src/xrpld/app/misc/NegativeUNLVote.h b/src/xrpld/app/misc/NegativeUNLVote.h index 95646af034..601ac7d060 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.h +++ b/src/xrpld/app/misc/NegativeUNLVote.h @@ -172,7 +172,7 @@ private: * @param scoreTable the score table * @return the candidates to disable and the candidates to re-enable */ - Candidates const + Candidates findAllCandidates( hash_set const& unl, hash_set const& negUnl, diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 18abab674d..d709981c46 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -752,7 +752,7 @@ private: DispatchState mDispatchState = DispatchState::none; std::vector mTransactions; - StateAccounting accounting_{}; + StateAccounting accounting_; std::set pendingValidations_; std::mutex validationsMutex_; @@ -1012,9 +1012,13 @@ NetworkOPsImp::processHeartbeatTimer() auto origMode = mMode.load(); CLOG(clog.ss()) << "mode: " << strOperatingMode(origMode, true); if (mMode == OperatingMode::SYNCING) + { setMode(OperatingMode::SYNCING); + } else if (mMode == OperatingMode::CONNECTED) + { setMode(OperatingMode::CONNECTED); + } auto newMode = mMode.load(); if (origMode != newMode) { @@ -1224,9 +1228,13 @@ NetworkOPsImp::processTransaction( return; if (bLocal) + { doTransactionSync(transaction, bUnlimited, failType); + } else + { doTransactionAsync(transaction, bUnlimited, failType); + } } void @@ -1287,7 +1295,7 @@ NetworkOPsImp::doTransactionSyncBatch( { apply(lock); - if (mTransactions.size()) + if (!mTransactions.empty()) { // More transactions need to be applied, but by another job. if (m_job_queue.addJob(jtBATCH, "TxBatchSync", [this]() { transactionBatch(); })) @@ -1342,7 +1350,9 @@ NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set) } if (mTransactions.empty()) + { mTransactions.swap(transactions); + } else { mTransactions.reserve(mTransactions.size() + transactions.size()); @@ -1371,7 +1381,7 @@ NetworkOPsImp::transactionBatch() if (mDispatchState == DispatchState::running) return; - while (mTransactions.size()) + while (!mTransactions.empty()) { apply(lock); } @@ -1606,7 +1616,9 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) if (!submit_held.empty()) { if (mTransactions.empty()) + { mTransactions.swap(submit_held); + } else { mTransactions.reserve(mTransactions.size() + submit_held.size()); @@ -1804,7 +1816,9 @@ NetworkOPsImp::checkLastClosedLedger(Overlay::PeerSequence const& peerList, uint switchLedgers = false; } else + { networkClosed = closedLedger; + } if (!switchLedgers) return false; @@ -1812,8 +1826,10 @@ NetworkOPsImp::checkLastClosedLedger(Overlay::PeerSequence const& peerList, uint auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger); if (!consensus) + { consensus = registry_.getInboundLedgers().acquire( closedLedger, 0, InboundLedger::Reason::CONSENSUS); + } if (consensus && (!m_ledgerMaster.canBeCurrent(consensus) || @@ -1865,9 +1881,13 @@ NetworkOPsImp::switchLastClosedLedger(std::shared_ptr const& newLC auto const lastVal = registry_.getLedgerMaster().getValidatedLedger(); std::optional rules; if (lastVal) + { rules = makeRulesGivenLedger(*lastVal, registry_.app().config().features); + } else + { rules.emplace(registry_.app().config().features); + } registry_.openLedger().accept( registry_.app(), *rules, @@ -2187,7 +2207,9 @@ NetworkOPsImp::pubServer() jvObj[jss::load_factor_fee_reference] = f.em->referenceFeeLevel.jsonClipped(); } else + { jvObj[jss::load_factor] = f.loadFactorServer; + } mLastFeeSummary = f; @@ -2411,9 +2433,13 @@ NetworkOPsImp::recvValidation(std::shared_ptr const& val, std::str try { if (pendingValidations_.contains(val->getLedgerHash())) + { bypassAccept = BypassAccept::yes; + } else + { pendingValidations_.insert(val->getLedgerHash()); + } scope_unlock unlock(lock); handleNewValidation(registry_.app(), val, source, bypassAccept, m_journal); } @@ -2555,10 +2581,14 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (!human) { if (when) + { info[jss::validator_list_expires] = safe_cast(when->time_since_epoch().count()); + } else + { info[jss::validator_list_expires] = 0; + } } else { @@ -2578,9 +2608,13 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) x[jss::expiration] = to_string(*when); if (*when > registry_.timeKeeper().now()) + { x[jss::status] = "active"; + } else + { x[jss::status] = "expired"; + } } } else @@ -2713,22 +2747,30 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) } if (escalationMetrics.openLedgerFeeLevel != escalationMetrics.referenceFeeLevel && (admin || loadFactorFeeEscalation != loadFactor)) + { info[jss::load_factor_fee_escalation] = escalationMetrics.openLedgerFeeLevel.decimalFromReference( escalationMetrics.referenceFeeLevel); + } if (escalationMetrics.minProcessingFeeLevel != escalationMetrics.referenceFeeLevel) + { info[jss::load_factor_fee_queue] = escalationMetrics.minProcessingFeeLevel.decimalFromReference( escalationMetrics.referenceFeeLevel); + } } bool valid = false; auto lpClosed = m_ledgerMaster.getValidatedLedger(); if (lpClosed) + { valid = true; + } else + { lpClosed = m_ledgerMaster.getClosedLedger(); + } if (lpClosed) { @@ -2775,15 +2817,23 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) } if (valid) + { info[jss::validated_ledger] = l; + } else + { info[jss::closed_ledger] = l; + } auto lpPublished = m_ledgerMaster.getPublishedLedger(); if (!lpPublished) + { info[jss::published_ledger] = "none"; + } else if (lpPublished->header().seq != lpClosed->header().seq) + { info[jss::published_ledger] = lpPublished->header().seq; + } } accounting_.json(info); @@ -2953,7 +3003,9 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) ++it; } else + { it = mStreamMaps[sLedger].erase(it); + } } } @@ -2971,7 +3023,9 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) ++it; } else + { it = mStreamMaps[sBookChanges].erase(it); + } } } @@ -3166,7 +3220,9 @@ NetworkOPsImp::pubValidatedTransaction( ++it; } else + { it = mStreamMaps[sTransactions].erase(it); + } } it = mStreamMaps[sRTTransactions].begin(); @@ -3183,7 +3239,9 @@ NetworkOPsImp::pubValidatedTransaction( ++it; } else + { it = mStreamMaps[sRTTransactions].erase(it); + } } } @@ -3228,7 +3286,9 @@ NetworkOPsImp::pubAccountTransaction( ++iProposed; } else + { it = simiIt->second.erase(it); + } } } @@ -3246,7 +3306,9 @@ NetworkOPsImp::pubAccountTransaction( ++iAccepted; } else + { it = simiIt->second.erase(it); + } } } @@ -3360,7 +3422,9 @@ NetworkOPsImp::pubProposedAccountTransaction( ++iProposed; } else + { it = simiIt->second.erase(it); + } } } } @@ -3375,9 +3439,11 @@ NetworkOPsImp::pubProposedAccountTransaction( MultiApiJson jvObj = transJson(tx, result, false, ledger, std::nullopt); for (InfoSub::ref isrListener : notify) + { jvObj.visit( isrListener->getApiVersion(), // [&](Json::Value const& jv) { isrListener->send(jv, true); }); + } XRPL_ASSERT( jvObj.isMember(jss::account_history_tx_stream) == MultiApiJson::none, @@ -3729,10 +3795,8 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) << " done, found last tx."; return; } - else - { - sendMultiApiJson(jvTx, false); - } + + sendMultiApiJson(jvTx, false); } if (marker) @@ -3892,7 +3956,9 @@ bool NetworkOPsImp::subBook(InfoSub::ref isrListener, Book const& book) { if (auto listeners = registry_.getOrderBookDB().makeBookListeners(book)) + { listeners->addSubscriber(isrListener); + } else { // LCOV_EXCL_START @@ -4150,7 +4216,7 @@ NetworkOPsImp::tryRemoveRpcSub(std::string const& strUrl) // this entry before removing for (SubMapType const& map : mStreamMaps) { - if (map.find(pInfo->getSeq()) != map.end()) + if (map.contains(pInfo->getSeq())) return false; } mRpcSubMap.erase(strUrl); @@ -4213,9 +4279,13 @@ NetworkOPsImp::getBookPage( auto const ledgerIndex = view.succ(uTipIndex, uBookEnd); if (ledgerIndex) + { sleOfferDir = view.read(keylet::page(*ledgerIndex)); + } else + { sleOfferDir.reset(); + } if (!sleOfferDir) { diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index 60dcd90388..13746369f5 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -143,7 +143,7 @@ SHAMapStoreImp::makeNodeStore(int readThreads) SavedState state = state_db_.getState(); auto writableBackend = makeBackendRotating(state.writableDb); auto archiveBackend = makeBackendRotating(state.archiveDb); - if (!state.writableDb.size()) + if (state.writableDb.empty()) { state.writableDb = writableBackend->getName(); state.archiveDb = archiveBackend->getName(); @@ -248,7 +248,9 @@ SHAMapStoreImp::run() validatedLedger = std::move(newLedger_); } else + { continue; + } } LedgerIndex const validatedSeq = validatedLedger->header().seq; @@ -385,15 +387,21 @@ SHAMapStoreImp::dbPaths() ++it) { if (!state.writableDb.compare(it->path().string())) + { writableDbExists = true; + } else if (!state.archiveDb.compare(it->path().string())) + { archiveDbExists = true; + } else if (!dbPrefix_.compare(it->path().stem().string())) + { pathsToDelete.push_back(it->path()); + } } - if ((!writableDbExists && state.writableDb.size()) || - (!archiveDbExists && state.archiveDb.size()) || (writableDbExists != archiveDbExists) || + if ((!writableDbExists && !state.writableDb.empty()) || + (!archiveDbExists && !state.archiveDb.empty()) || (writableDbExists != archiveDbExists) || state.writableDb.empty() != state.archiveDb.empty()) { boost::filesystem::path stateDbPathName = app_.config().legacy("database_path"); @@ -428,7 +436,7 @@ SHAMapStoreImp::makeBackendRotating(std::string path) Section section{app_.config().section(ConfigSection::nodeDatabase())}; boost::filesystem::path newPath; - if (path.size()) + if (!path.empty()) { newPath = path; } diff --git a/src/xrpld/app/misc/detail/AccountTxPaging.cpp b/src/xrpld/app/misc/detail/AccountTxPaging.cpp index 63457f00ac..4e79b53ed0 100644 --- a/src/xrpld/app/misc/detail/AccountTxPaging.cpp +++ b/src/xrpld/app/misc/detail/AccountTxPaging.cpp @@ -27,13 +27,17 @@ convertBlobsToTxResult( // if properly formed meta is available we can use it to generate ctid if (metaset->getAsObject().isFieldPresent(sfTransactionIndex)) + { tr->setStatus( Transaction::sqlTransactionStatus(status), ledger_index, metaset->getAsObject().getFieldU32(sfTransactionIndex), app.getNetworkIDService().getNetworkID()); + } else + { tr->setStatus(Transaction::sqlTransactionStatus(status), ledger_index); + } to.emplace_back(std::move(tr), metaset); }; diff --git a/src/xrpld/app/misc/detail/AmendmentTable.cpp b/src/xrpld/app/misc/detail/AmendmentTable.cpp index 5bdd604828..2b7005f4cc 100644 --- a/src/xrpld/app/misc/detail/AmendmentTable.cpp +++ b/src/xrpld/app/misc/detail/AmendmentTable.cpp @@ -40,8 +40,10 @@ parseSection(Section const& section) uint256 id; if (!id.parseHex(match[1])) + { Throw( "Invalid amendment ID '" + match[1] + "' in [" + section.name() + "]"); + } names.push_back(std::make_pair(id, match[2])); } @@ -525,11 +527,10 @@ AmendmentTableImpl::AmendmentTableImpl( " in favor of data in db/wallet.db."; break; } - else - { // Otherwise transfer config data into the table - detect_conflict.insert(a.first); - persistVote(a.first, a.second, AmendmentVote::up); - } + + // Otherwise transfer config data into the table + detect_conflict.insert(a.first); + persistVote(a.first, a.second, AmendmentVote::up); } // Parse vetoed amendments from config @@ -541,18 +542,17 @@ AmendmentTableImpl::AmendmentTableImpl( " in favor of data in db/wallet.db."; break; } + + // Otherwise transfer config data into the table + if (!detect_conflict.contains(a.first)) + { + persistVote(a.first, a.second, AmendmentVote::down); + } else - { // Otherwise transfer config data into the table - if (detect_conflict.count(a.first) == 0) - { - persistVote(a.first, a.second, AmendmentVote::down); - } - else - { - JLOG(j_.warn()) << "[veto_amendments] section in config has amendment " << '(' - << a.first << ", " << a.second - << ") both [veto_amendments] and [amendments]."; - } + { + JLOG(j_.warn()) << "[veto_amendments] section in config has amendment " << '(' + << a.first << ", " << a.second + << ") both [veto_amendments] and [amendments]."; } } @@ -745,7 +745,7 @@ AmendmentTableImpl::doValidation(std::set const& enabled) const for (auto const& e : amendmentMap_) { if (e.second.supported && e.second.vote == AmendmentVote::up && - (enabled.count(e.first) == 0)) + (!enabled.contains(e.first))) { amendments.push_back(e.first); JLOG(j_.info()) << "Voting for amendment " << e.second.name; @@ -927,9 +927,13 @@ AmendmentTableImpl::injectJson( if (!fs.enabled && isAdmin) { if (fs.vote == AmendmentVote::obsolete) + { v[jss::vetoed] = "Obsolete"; + } else + { v[jss::vetoed] = fs.vote == AmendmentVote::down; + } } v[jss::enabled] = fs.enabled; diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index 0dd0fc1063..2b90cb8161 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -386,23 +386,29 @@ TxQ::canBeHeld( // transaction fills the _first_ sequence hole for the account. auto const txSeqProx = tx.getSeqProxy(); if (txSeqProx.isTicket()) + { // Tickets always follow sequence-based transactions, so a ticket // cannot unblock a sequence-based transaction. return telCAN_NOT_QUEUE_FULL; + } // This is the next queuable sequence-based SeqProxy for the account. SeqProxy const nextQueuable = nextQueuableSeqImpl(sleAccount, lock); if (txSeqProx != nextQueuable) + { // The provided transaction does not fill the next open sequence gap. return telCAN_NOT_QUEUE_FULL; + } // Make sure they are not just topping off the account's queued // sequence-based transactions. if (auto const nextTxIter = txQAcct.transactions.upper_bound(nextQueuable); nextTxIter != txQAcct.transactions.end() && nextTxIter->first.isSeq()) + { // There is a next transaction and it is sequence based. They are // filling a real gap. Allow it. return tesSUCCESS; + } return telCAN_NOT_QUEUE_FULL; } @@ -718,9 +724,11 @@ TxQ::apply( if (txSeqProx.isTicket() && !view.exists(keylet::ticket(account, txSeqProx))) { if (txSeqProx.value() < acctSeqProx.value()) + { // The ticket number is low enough that it should already be // in the ledger if it were ever going to exist. return {tefNO_TICKET, false}; + } // We don't queue transactions that use Tickets unless // we can find the Ticket in the ledger. @@ -762,9 +770,11 @@ TxQ::apply( TxQAccount::TxMap::iterator const firstIter = acctTxs.lower_bound(acctSeqProx); if (firstIter == acctTxs.end()) + { // Even though there may be transactions in the queue, there are // none that we should pay attention to. return {}; + } return {TxIter{firstIter, acctTxs.end()}}; }(); @@ -949,9 +959,13 @@ TxQ::apply( if (txSeqProx.isSeq()) { if (txSeqProx < acctSeqProx) + { return {tefPAST_SEQ, false}; - else if (txSeqProx > acctSeqProx) + } + if (txSeqProx > acctSeqProx) + { return {terPRE_SEQ, false}; + } } } else if (!replacedTxIter) @@ -1301,9 +1315,13 @@ TxQ::processClosedLedger(Application& app, ReadView const& view, bool timeLeap) for (auto txQAccountIter = byAccount_.begin(); txQAccountIter != byAccount_.end();) { if (txQAccountIter->second.empty()) + { txQAccountIter = byAccount_.erase(txQAccountIter); + } else + { ++txQAccountIter; + } } } @@ -1393,9 +1411,13 @@ TxQ::accept(Application& app, OpenView& view) candidateIter->retriesRemaining <= 0) { if (candidateIter->retriesRemaining <= 0) + { account.retryPenalty = true; + } else + { account.dropPenalty = true; + } JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID << " failed with " << transToken(txnResult) << ". Remove from queue."; candidateIter = eraseAndAdvance(candidateIter); @@ -1406,9 +1428,13 @@ TxQ::accept(Application& app, OpenView& view) << transToken(txnResult) << ". Leave in queue." << " Applied: " << didApply << ". Flags: " << candidateIter->flags; if (account.retryPenalty && candidateIter->retriesRemaining > 2) + { candidateIter->retriesRemaining = 1; + } else + { --candidateIter->retriesRemaining; + } candidateIter->lastResult = txnResult; if (account.dropPenalty && account.transactions.size() > 1 && isFull<95>()) { @@ -1447,7 +1473,9 @@ TxQ::accept(Application& app, OpenView& view) } } else + { ++candidateIter; + } } } else @@ -1462,9 +1490,13 @@ TxQ::accept(Application& app, OpenView& view) // reordered. LedgerHash const& parentHash = view.header().parentHash; if (parentHash == parentHash_) + { JLOG(j_.warn()) << "Parent ledger hash unchanged from " << parentHash; + } else + { parentHash_ = parentHash; + } [[maybe_unused]] auto const startingSize = byFee_.size(); // byFee_ doesn't "own" the candidate objects inside it, so it's @@ -1532,12 +1564,14 @@ TxQ::nextQueuableSeqImpl( TxQAccount::TxMap::const_iterator txIter = acctTxs.lower_bound(acctSeqProx); if (txIter == acctTxs.end() || !txIter->first.isSeq() || txIter->first != acctSeqProx) + { // Either... // o There are no queued sequence-based transactions equal to or // following acctSeqProx or // o acctSeqProx is not currently in the queue. // So acctSeqProx is as good as it gets. return acctSeqProx; + } // There are sequence-based transactions queued that follow acctSeqProx. // Locate the first opening to put a transaction into. diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 73db2f8bdb..386b96387e 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -158,7 +158,7 @@ ValidatorList::load( status = PublisherStatus::revoked; } - if (publisherLists_.count(id)) + if (publisherLists_.contains(id)) { JLOG(j_.warn()) << "Duplicate validator list publisher key: " << key; continue; @@ -508,34 +508,29 @@ splitMessageParts( 1); return messages.back().numVLs; } - else + + std::optional smallMsg; + smallMsg.emplace(); + smallMsg->set_version(largeMsg.version()); + smallMsg->set_manifest(largeMsg.manifest()); + + for (std::size_t i = begin; i < end; ++i) { - std::optional smallMsg; - smallMsg.emplace(); - smallMsg->set_version(largeMsg.version()); - smallMsg->set_manifest(largeMsg.manifest()); - - for (std::size_t i = begin; i < end; ++i) - { - *smallMsg->add_blobs() = largeMsg.blobs(i); - } - - if (Message::totalSize(*smallMsg) > maxSize) - { - // free up the message space - smallMsg.reset(); - return splitMessage(messages, largeMsg, maxSize, begin, end); - } - else - { - messages.emplace_back( - std::make_shared(*smallMsg, protocol::mtVALIDATOR_LIST_COLLECTION), - sha512Half(*smallMsg), - smallMsg->blobs_size()); - return messages.back().numVLs; - } + *smallMsg->add_blobs() = largeMsg.blobs(i); } - return 0; + + if (Message::totalSize(*smallMsg) > maxSize) + { + // free up the message space + smallMsg.reset(); + return splitMessage(messages, largeMsg, maxSize, begin, end); + } + + messages.emplace_back( + std::make_shared(*smallMsg, protocol::mtVALIDATOR_LIST_COLLECTION), + sha512Half(*smallMsg), + smallMsg->blobs_size()); + return messages.back().numVLs; } // Build a v1 protocol message using only the current VL @@ -608,14 +603,12 @@ buildValidatorListMessage( // split into smaller messages return splitMessage(messages, msg, maxSize); } - else - { - messages.emplace_back( - std::make_shared(msg, protocol::mtVALIDATOR_LIST_COLLECTION), - sha512Half(msg), - msg.blobs_size()); - return messages.back().numVLs; - } + + messages.emplace_back( + std::make_shared(msg, protocol::mtVALIDATOR_LIST_COLLECTION), + sha512Half(msg), + msg.blobs_size()); + return messages.back().numVLs; } [[nodiscard]] @@ -648,15 +641,17 @@ ValidatorList::buildValidatorListMessages( numVLs = buildValidatorListMessage( messages, peerSequence, rawVersion, rawManifest, blobInfos, maxSize); if (messages.empty()) + { // No message was generated. Create an empty placeholder so we // dont' repeat the work later. messages.emplace_back(); + } } // Don't send it next time. return {maxSequence, numVLs}; } - else if (messageVersion == 1 && peerSequence < currentSeq) + if (messageVersion == 1 && peerSequence < currentSeq) { // Version 1 if (messages.empty()) @@ -668,9 +663,11 @@ ValidatorList::buildValidatorListMessages( currentBlob, maxSize); if (messages.empty()) + { // No message was generated. Create an empty placeholder so we // dont' repeat the work later. messages.emplace_back(); + } } // Don't send it next time. @@ -693,10 +690,15 @@ ValidatorList::sendValidatorList( HashRouter& hashRouter, beast::Journal j) { - std::size_t const messageVersion = - peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) ? 2 - : peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1 - : 0; + std::size_t messageVersion = 0; + if (peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation)) + { + messageVersion = 2; + } + else if (peer.supportsFeature(ProtocolFeature::ValidatorListPropagation)) + { + messageVersion = 1; + } if (!messageVersion) return; auto const [newPeerSequence, numVLs] = buildValidatorListMessages( @@ -728,11 +730,13 @@ ValidatorList::sendValidatorList( if (sent) { if (messageVersion > 1) + { JLOG(j.debug()) << "Sent " << messages.size() << " validator list collection(s) containing " << numVLs << " validator list(s) for " << strHex(publisherKey) << " with sequence range " << peerSequence << ", " << newPeerSequence << " to " << peer.fingerprint(); + } else { XRPL_ASSERT( @@ -835,7 +839,7 @@ ValidatorList::broadcastBlobs( // the peer, and foreach provides a const& for (auto& peer : overlay.getActivePeers()) { - if (toSkip->count(peer->id()) == 0) + if (!toSkip->contains(peer->id())) { auto const peerSequence = peer->publisherListSequence(publisherKey).value_or(0); if (peerSequence < maxSequence) @@ -955,13 +959,15 @@ ValidatorList::applyLists( result = std::move(stats); } else + { result.mergeDispositions(stats); + } ///////// } // Clean up the collection, because some of the processing may have made it // inconsistent - if (result.publisherKey && publisherLists_.count(*result.publisherKey)) + if (result.publisherKey && publisherLists_.contains(*result.publisherKey)) { auto& pubCollection = publisherLists_[*result.publisherKey]; auto& remaining = pubCollection.remaining; @@ -1017,9 +1023,13 @@ ValidatorList::updatePublisherList( { // Decrement list count for removed keys if (keyListings_[*iOld] <= 1) + { keyListings_.erase(*iOld); + } else + { --keyListings_[*iOld]; + } ++iOld; } else @@ -1038,7 +1048,7 @@ ValidatorList::updatePublisherList( { auto m = deserializeManifest(base64_decode(valManifest)); - if (!m || !keyListings_.count(m->masterKey)) + if (!m || !keyListings_.contains(m->masterKey)) { JLOG(j_.warn()) << "List for " << strHex(pubKey) << " contained untrusted validator manifest"; @@ -1099,7 +1109,7 @@ ValidatorList::applyList( PublicKey pubKey = *pubKeyOpt; if (result > ListDisposition::pending) { - if (publisherLists_.count(pubKey)) + if (publisherLists_.contains(pubKey)) { auto const& pubCollection = publisherLists_[pubKey]; if (pubCollection.maxSequence && @@ -1122,15 +1132,17 @@ ValidatorList::applyList( (result == ListDisposition::accepted || result == ListDisposition::expired); if (accepted) + { pubCollection.status = result == ListDisposition::accepted ? PublisherStatus::available : PublisherStatus::expired; + } pubCollection.rawManifest = globalManifest; if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence) pubCollection.maxSequence = sequence; Json::Value const& newList = list[jss::validators]; std::vector oldList; - if (accepted && pubCollection.remaining.count(sequence) != 0) + if (accepted && pubCollection.remaining.contains(sequence)) { // We've seen this list before and stored it in "remaining". The // normal expected process is that the processed list would have @@ -1282,7 +1294,7 @@ ValidatorList::verify( std::string const& blob, std::string const& signature) { - if (!publisherLists_.count(manifest.masterKey)) + if (!publisherLists_.contains(manifest.masterKey)) return {ListDisposition::untrusted, {}}; PublicKey masterPubKey = manifest.masterKey; @@ -1324,14 +1336,23 @@ ValidatorList::verify( auto const now = timeKeeper_.now(); auto const& listCollection = publisherLists_[masterPubKey]; if (validUntil <= validFrom) + { return {ListDisposition::invalid, masterPubKey}; - else if (sequence < listCollection.current.sequence) + } + if (sequence < listCollection.current.sequence) + { return {ListDisposition::stale, masterPubKey}; - else if (sequence == listCollection.current.sequence) + } + if (sequence == listCollection.current.sequence) + { return {ListDisposition::same_sequence, masterPubKey}; - else if (validUntil <= now) + } + if (validUntil <= now) + { return {ListDisposition::expired, masterPubKey}; - else if (validFrom > now) + } + if (validFrom > now) + { // Not yet valid. Return pending if one of the following is true // * There's no maxSequence, indicating this is the first blob seen // for this publisher @@ -1343,10 +1364,11 @@ ValidatorList::verify( // prevents the risk of missing valid data. Else return // known_sequence return !listCollection.maxSequence || sequence > *listCollection.maxSequence || - (listCollection.remaining.count(sequence) == 0 && + (!listCollection.remaining.contains(sequence) && validFrom < listCollection.remaining.at(*listCollection.maxSequence).validFrom) ? std::make_pair(ListDisposition::pending, masterPubKey) : std::make_pair(ListDisposition::known_sequence, masterPubKey); + } } else { @@ -1362,14 +1384,14 @@ ValidatorList::listed(PublicKey const& identity) const std::shared_lock read_lock{mutex_}; auto const pubKey = validatorManifests_.getMasterKey(identity); - return keyListings_.find(pubKey) != keyListings_.end(); + return keyListings_.contains(pubKey); } bool ValidatorList::trusted(ValidatorList::shared_lock const&, PublicKey const& identity) const { auto const pubKey = validatorManifests_.getMasterKey(identity); - return trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end(); + return trustedMasterKeys_.contains(pubKey); } bool @@ -1385,7 +1407,7 @@ ValidatorList::getListedKey(PublicKey const& identity) const std::shared_lock read_lock{mutex_}; auto const pubKey = validatorManifests_.getMasterKey(identity); - if (keyListings_.find(pubKey) != keyListings_.end()) + if (keyListings_.contains(pubKey)) return pubKey; return std::nullopt; } @@ -1394,7 +1416,7 @@ std::optional ValidatorList::getTrustedKey(ValidatorList::shared_lock const&, PublicKey const& identity) const { auto const pubKey = validatorManifests_.getMasterKey(identity); - if (trustedMasterKeys_.find(pubKey) != trustedMasterKeys_.end()) + if (trustedMasterKeys_.contains(pubKey)) return pubKey; return std::nullopt; } @@ -1411,7 +1433,7 @@ bool ValidatorList::trustedPublisher(PublicKey const& identity) const { std::shared_lock read_lock{mutex_}; - return identity.size() && publisherLists_.count(identity) && + return identity.size() && publisherLists_.contains(identity) && publisherLists_.at(identity).status < PublisherStatus::revoked; } @@ -1444,9 +1466,13 @@ ValidatorList::removePublisherList( continue; if (iVal->second <= 1) + { keyListings_.erase(iVal); + } else + { --iVal->second; + } } iList->second.current.list.clear(); @@ -1458,7 +1484,7 @@ ValidatorList::removePublisherList( std::size_t ValidatorList::count(ValidatorList::shared_lock const&) const { - return publisherLists_.size() + (localPublisherList.list.size() > 0); + return publisherLists_.size() + (!localPublisherList.list.empty()); } std::size_t @@ -1489,9 +1515,13 @@ ValidatorList::expires(ValidatorList::shared_lock const&) const { (void)sequence; if (check.validFrom <= chainedExpiration) + { chainedExpiration = check.validUntil; + } else + { break; + } } // Earliest @@ -1501,7 +1531,7 @@ ValidatorList::expires(ValidatorList::shared_lock const&) const } } - if (localPublisherList.list.size() > 0) + if (!localPublisherList.list.empty()) { PublisherList collection = localPublisherList; // Unfetched @@ -1550,9 +1580,13 @@ ValidatorList::getJson() const x[jss::expiration] = to_string(*when); if (*when > timeKeeper_.now()) + { x[jss::status] = "active"; + } else + { x[jss::status] = "expired"; + } } } else @@ -1951,7 +1985,7 @@ ValidatorList::updateTrusted( { for (auto const& k : trustedMasterKeys_) { - if (negativeUNL_.count(k)) + if (negativeUNL_.contains(k)) --effectiveUnlSize; } hash_set negUnlNodeIDs; @@ -1961,7 +1995,7 @@ ValidatorList::updateTrusted( } for (auto const& nid : seenValidators) { - if (negUnlNodeIDs.count(nid)) + if (negUnlNodeIDs.contains(nid)) --seenSize; } } @@ -1977,7 +2011,7 @@ ValidatorList::updateTrusted( << " exceeds the number of trusted validators (" << unlSize << ")"; } - if ((publisherLists_.size() || localPublisherList.list.size()) && unlSize == 0) + if ((!publisherLists_.empty() || !localPublisherList.list.empty()) && unlSize == 0) { // No validators. Lock down. ops.setUNLBlocked(); @@ -2031,12 +2065,10 @@ ValidatorList::negativeUNLFilter(std::vector>&& va if (auto const masterKey = getTrustedKey(read_lock, v->getSignerPublic()); masterKey) { - return negativeUNL_.count(*masterKey); - } - else - { - return false; + return negativeUNL_.contains(*masterKey); } + + return false; }), ret.end()); } diff --git a/src/xrpld/app/misc/detail/ValidatorSite.cpp b/src/xrpld/app/misc/detail/ValidatorSite.cpp index 0a207c344c..8db29c0bb0 100644 --- a/src/xrpld/app/misc/detail/ValidatorSite.cpp +++ b/src/xrpld/app/misc/detail/ValidatorSite.cpp @@ -52,7 +52,9 @@ ValidatorSite::Site::Resource::Resource(std::string uri_) : uri{std::move(uri_)} pUrl.port = 443; } else + { throw std::runtime_error("Unsupported scheme: '" + pUrl.scheme + "'"); + } } ValidatorSite::Site::Site(std::string uri) @@ -61,7 +63,6 @@ ValidatorSite::Site::Site(std::string uri) , redirCount{0} , refreshInterval{default_refresh_interval} , nextRefresh{clock_type::now()} - , lastRequestEndpoint{} , lastRequestSuccessful{false} { } @@ -301,7 +302,9 @@ ValidatorSite::onRequestTimeout(std::size_t siteIdx, error_code const& ec) // first, which will leave activeResource empty. auto const& site = sites_[siteIdx]; if (site.activeResource) + { JLOG(j_.warn()) << "Request for " << site.activeResource->uri << " took too long"; + } else JLOG(j_.error()) << "Request took too long, but a response has " "already been processed"; @@ -459,7 +462,7 @@ ValidatorSite::processRedirect( { using namespace boost::beast::http; std::shared_ptr newLocation; - if (res.find(field::location) == res.end() || res[field::location].empty()) + if (!res.contains(field::location) || res[field::location].empty()) { JLOG(j_.warn()) << "Request for validator list at " << sites_[siteIdx].activeResource->uri << " returned a redirect with no Location."; diff --git a/src/xrpld/app/misc/detail/WorkSSL.cpp b/src/xrpld/app/misc/detail/WorkSSL.cpp index 47902e900a..3ae0db1a96 100644 --- a/src/xrpld/app/misc/detail/WorkSSL.cpp +++ b/src/xrpld/app/misc/detail/WorkSSL.cpp @@ -32,7 +32,10 @@ WorkSSL::onConnect(error_code const& ec) { auto err = ec ? ec : context_.postConnectVerify(stream_, host_); if (err) - return fail(err); + { + fail(err); + return; + } stream_.async_handshake( boost::asio::ssl::stream_base::client, @@ -44,7 +47,10 @@ void WorkSSL::onHandshake(error_code const& ec) { if (ec) - return fail(ec); + { + fail(ec); + return; + } onStart(); } diff --git a/src/xrpld/app/misc/detail/setup_HashRouter.cpp b/src/xrpld/app/misc/detail/setup_HashRouter.cpp index a0e63dd67e..0cc61f0730 100644 --- a/src/xrpld/app/misc/detail/setup_HashRouter.cpp +++ b/src/xrpld/app/misc/detail/setup_HashRouter.cpp @@ -18,17 +18,21 @@ setup_HashRouter(Config const& config) if (set(tmp, "hold_time", section)) { if (tmp < 12) + { Throw( "HashRouter hold time must be at least 12 seconds (the " "approximate validation time for three ledgers)."); + } setup.holdTime = seconds(tmp); } if (set(tmp, "relay_time", section)) { if (tmp < 8) + { Throw( "HashRouter relay time must be at least 8 seconds (the " "approximate validation time for two ledgers)."); + } setup.relayTime = seconds(tmp); } if (setup.relayTime > setup.holdTime) diff --git a/src/xrpld/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp index b3758a690b..f82a207552 100644 --- a/src/xrpld/app/paths/PathRequest.cpp +++ b/src/xrpld/app/paths/PathRequest.cpp @@ -406,10 +406,8 @@ PathRequest::parseJson(Json::Value const& jvParams) jvStatus = rpcError(rpcDOMAIN_MALFORMED); return PFR_PJ_INVALID; } - else - { - domain = num; - } + + domain = num; } return PFR_PJ_NOCHANGE; @@ -461,9 +459,13 @@ PathRequest::getPathFinder( domain, app_); if (pathfinder->findPaths(level, continueCallback)) + { pathfinder->computePathRanks(max_paths_, continueCallback); + } else + { pathfinder.reset(); // It's a bad request - clear it. + } return currency_map[currency] = std::move(pathfinder); } @@ -652,9 +654,13 @@ PathRequest::doUpdate( { // first pass if (loaded || fast) + { iLevel = app_.config().PATH_SEARCH_FAST; + } else + { iLevel = app_.config().PATH_SEARCH; + } } else if ((iLevel == app_.config().PATH_SEARCH_FAST) && !fast) { diff --git a/src/xrpld/app/paths/PathRequests.cpp b/src/xrpld/app/paths/PathRequests.cpp index 35a6c7aa48..61db1e58ef 100644 --- a/src/xrpld/app/paths/PathRequests.cpp +++ b/src/xrpld/app/paths/PathRequests.cpp @@ -95,7 +95,9 @@ PathRequests::updateAll(std::shared_ptr const& inLedger) return (bool)getSubscriber(request); }; if (!request->needsUpdate(newRequests, cache->getLedger()->seq())) + { remove = false; + } else { if (auto ipSub = getSubscriber(request)) diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index 38d4488663..c777fcb2f7 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -95,7 +95,7 @@ struct PathCost }; using PathCostList = std::vector; -static PathTable mPathTable; +PathTable mPathTable; std::string pathTypeToString(Pathfinder::PathType const& type) @@ -574,17 +574,29 @@ Pathfinder::getBestPaths( bool useExtraPath = false; if (pathsIterator == mPathRanks.end()) + { useExtraPath = true; + } else if (extraPathsIterator == extraPathRanks.end()) + { usePath = true; + } else if (extraPathsIterator->quality < pathsIterator->quality) + { useExtraPath = true; + } else if (extraPathsIterator->quality > pathsIterator->quality) + { usePath = true; + } else if (extraPathsIterator->liquidity > pathsIterator->liquidity) + { useExtraPath = true; + } else if (extraPathsIterator->liquidity < pathsIterator->liquidity) + { usePath = true; + } else { // Risk is high they have identical liquidity @@ -1020,9 +1032,13 @@ Pathfinder::addLink( int count = candidates.size(); // allow more paths from source if ((count > 10) && (uEndAccount != mSrcAccount)) + { count = 10; + } else if (count > 50) + { count = 50; + } auto it = candidates.begin(); while (count-- != 0) @@ -1090,7 +1106,9 @@ Pathfinder::addLink( addUniquePath(mCompletePaths, newPath); } else + { incompletePaths.push_back(newPath); + } } else if (!currentPath.hasSeen( book.out.account, book.out.currency, book.out.account)) diff --git a/src/xrpld/app/paths/RippleLineCache.cpp b/src/xrpld/app/paths/RippleLineCache.cpp index 9916facdc2..ac3e28e579 100644 --- a/src/xrpld/app/paths/RippleLineCache.cpp +++ b/src/xrpld/app/paths/RippleLineCache.cpp @@ -76,7 +76,7 @@ RippleLineCache::getRippleLines(AccountID const& accountID, LineDirection direct { XRPL_ASSERT(it->second == nullptr, "xrpl::RippleLineCache::getRippleLines : null lines"); auto lines = PathFindTrustLine::getItems(accountID, *ledger_, direction); - if (lines.size()) + if (!lines.empty()) { it->second = std::make_shared>(std::move(lines)); totalLineCount_ += it->second->size(); diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index 3ffc86d1ba..72ee8eb261 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -80,11 +80,17 @@ constexpr T maxAmount() { if constexpr (std::is_same_v) + { return XRPAmount(STAmount::cMaxNative); + } else if constexpr (std::is_same_v) + { return IOUAmount(STAmount::cMaxValue / 2, STAmount::cMaxOffset); + } else if constexpr (std::is_same_v) + { return STAmount(STAmount::cMaxValue / 2, STAmount::cMaxOffset); + } } template @@ -108,14 +114,12 @@ AMMLiquidity::maxOffer(TAmounts const& balances, Rules con balances, Quality{balances}); } - else - { - auto const out = maxOut(balances.out, issueOut()); - if (out <= TOut{0} || out >= balances.out) - return std::nullopt; - return AMMOffer( - *this, {swapAssetOut(balances, out, tradingFee_), out}, balances, Quality{balances}); - } + + auto const out = maxOut(balances.out, issueOut()); + if (out <= TOut{0} || out >= balances.out) + return std::nullopt; + return AMMOffer( + *this, {swapAssetOut(balances, out, tradingFee_), out}, balances, Quality{balances}); } template @@ -166,7 +170,7 @@ AMMLiquidity::getOffer(ReadView const& view, std::optional c return std::nullopt; return AMMOffer(*this, amounts, balances, Quality{amounts}); } - else if (!clobQuality) + if (!clobQuality) { // If there is no CLOB to compare against, return the largest // amount, which doesn't overflow. The size is going to be @@ -175,13 +179,12 @@ AMMLiquidity::getOffer(ReadView const& view, std::optional c // nullopt if the pool is small. return maxOffer(balances, view.rules()); } - else if ( - auto const amounts = + if (auto const amounts = changeSpotPriceQuality(balances, *clobQuality, tradingFee_, view.rules(), j_)) { return AMMOffer(*this, *amounts, balances, Quality{*amounts}); } - else if (view.rules().enabled(fixAMMv1_2)) + if (view.rules().enabled(fixAMMv1_2)) { if (auto const maxAMMOffer = maxOffer(balances, view.rules()); maxAMMOffer && Quality{maxAMMOffer->amount()} > *clobQuality) @@ -192,9 +195,11 @@ AMMLiquidity::getOffer(ReadView const& view, std::optional c { JLOG(j_.error()) << "AMMLiquidity::getOffer overflow " << e.what(); if (!view.rules().enabled(fixAMMOverflowOffer)) + { return maxOffer(balances, view.rules()); - else - return std::nullopt; + } + + return std::nullopt; } catch (std::exception const& e) { diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index 37ca16c72d..ae0c371e3e 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -74,6 +74,7 @@ private: { if (auto const ammSle = ctx.view.read(keylet::amm(in, out)); ammSle && ammSle->getFieldAmount(sfLPTokenBalance) != beast::zero) + { ammLiquidity_.emplace( ctx.view, (*ammSle)[sfAccount], @@ -82,6 +83,7 @@ private: out, ctx.ammContext, ctx.j); + } } public: @@ -491,11 +493,14 @@ public: // when calculating the upper bound quality and the quality function // because single path AMM's offer quality is not constant. if (!rules.enabled(fixAMMv1_1)) + { return ofrQ; - else if ( - offerType == OfferType::CLOB || + } + if (offerType == OfferType::CLOB || (this->ammLiquidity_ && this->ammLiquidity_->multiPath())) + { return ofrQ; + } auto rate = [&](AccountID const& id) { if (isXRP(id) || id == this->strandDst_) @@ -674,9 +679,13 @@ BookStep::forEachOffer( // Note that offer.quality() returns a (non-optional) Quality. So // ofrQ is always safe to use below this point in the lambda. if (!ofrQ) + { ofrQ = offer.quality(); + } else if (*ofrQ != offer.quality()) + { return false; + } if (static_cast(this)->limitSelfCrossQuality( strandSrc_, strandDst_, offer, ofrQ, offers, offerAttempted)) @@ -704,8 +713,10 @@ BookStep::forEachOffer( if (auto const key = offer.key()) offers.permRmOffer(*key); if (!offerAttempted) + { // Change quality only if no previous offers were tried. ofrQ = std::nullopt; + } // Returning true causes offers.step() to delete the offer. return true; } @@ -881,24 +892,34 @@ auto BookStep::tipOfferQuality(ReadView const& view) const -> std::optional> { - if (auto const res = tip(view); !res) + auto const res = tip(view); + if (!res) + { return std::nullopt; - else if (auto const q = std::get_if(&(*res))) + } + if (auto const q = std::get_if(&(*res))) + { return std::make_pair(*q, OfferType::CLOB); - else - return std::make_pair(std::get>(*res).quality(), OfferType::AMM); + } + + return std::make_pair(std::get>(*res).quality(), OfferType::AMM); } template std::optional BookStep::tipOfferQualityF(ReadView const& view) const { - if (auto const res = tip(view); !res) + auto const res = tip(view); + if (!res) + { return std::nullopt; - else if (auto const q = std::get_if(&(*res))) + } + if (auto const q = std::get_if(&(*res))) + { return QualityFunction{*q, QualityFunction::CLOBLikeTag{}}; - else - return std::get>(*res).getQualityFunc(); + } + + return std::get>(*res).getQualityFunc(); } template @@ -954,33 +975,31 @@ BookStep::revImp( // we need to consume the offer return true; } - else - { - auto ofrAdjAmt = ofrAmt; - auto stpAdjAmt = stpAmt; - auto ownerGivesAdj = ownerGives; - limitStepOut( - offer, - ofrAdjAmt, - stpAdjAmt, - ownerGivesAdj, - transferRateIn, - transferRateOut, - remainingOut); - remainingOut = beast::zero; - savedIns.insert(stpAdjAmt.in); - savedOuts.insert(remainingOut); - result.in = sum(savedIns); - result.out = out; - this->consumeOffer(sb, offer, ofrAdjAmt, stpAdjAmt, ownerGivesAdj); - // Explicitly check whether the offer is funded. Given that we have - // (stpAmt.out > remainingOut), it's natural to assume the offer - // will still be funded after consuming remainingOut but that is - // not always the case. If the mantissas of two IOU amounts differ - // by less than ten, then subtracting them leaves a zero. - return offer.fully_consumed(); - } + auto ofrAdjAmt = ofrAmt; + auto stpAdjAmt = stpAmt; + auto ownerGivesAdj = ownerGives; + limitStepOut( + offer, + ofrAdjAmt, + stpAdjAmt, + ownerGivesAdj, + transferRateIn, + transferRateOut, + remainingOut); + remainingOut = beast::zero; + savedIns.insert(stpAdjAmt.in); + savedOuts.insert(remainingOut); + result.in = sum(savedIns); + result.out = out; + this->consumeOffer(sb, offer, ofrAdjAmt, stpAdjAmt, ownerGivesAdj); + + // Explicitly check whether the offer is funded. Given that we have + // (stpAmt.out > remainingOut), it's natural to assume the offer + // will still be funded after consuming remainingOut but that is + // not always the case. If the mantissas of two IOU amounts differ + // by less than ten, then subtracting them leaves a zero. + return offer.fully_consumed(); }; { diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index dab16f010d..a07e5824d6 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -335,18 +335,20 @@ DirectIPaymentStep::quality(ReadView const& sb, QualityDirection qDir) const { // compute dst quality in if (this->dst_ < this->src_) + { return sfLowQualityIn; - else - return sfHighQualityIn; + } + + return sfHighQualityIn; } - else + + // compute src quality out + if (this->src_ < this->dst_) { - // compute src quality out - if (this->src_ < this->dst_) - return sfLowQualityOut; - else - return sfHighQualityOut; + return sfLowQualityOut; } + + return sfHighQualityOut; }(); if (!sle->isFieldPresent(field)) @@ -756,15 +758,13 @@ DirectStepI::qualities( { return qualitiesSrcRedeems(sb); } - else - { - auto const prevStepDebtDirection = [&] { - if (prevStep_) - return prevStep_->debtDirection(sb, strandDir); - return DebtDirection::issues; - }(); - return qualitiesSrcIssues(sb, prevStepDebtDirection); - } + + auto const prevStepDebtDirection = [&] { + if (prevStep_) + return prevStep_->debtDirection(sb, strandDir); + return DebtDirection::issues; + }(); + return qualitiesSrcIssues(sb, prevStepDebtDirection); } template diff --git a/src/xrpld/app/paths/detail/PaySteps.cpp b/src/xrpld/app/paths/detail/PaySteps.cpp index e438d4442a..9087647aeb 100644 --- a/src/xrpld/app/paths/detail/PaySteps.cpp +++ b/src/xrpld/app/paths/detail/PaySteps.cpp @@ -264,9 +264,13 @@ toStrand( auto const next = &normPath[i + 1]; if (cur->isAccount()) + { curIssue.account = cur->getAccountID(); + } else if (cur->hasIssuer()) + { curIssue.account = cur->getIssuerID(); + } if (cur->hasCurrency()) { @@ -314,14 +318,12 @@ toStrand( { if (i != normPath.size() - 2) return {temBAD_PATH, Strand{}}; - else - { - // Last step. insert xrp endpoint step - auto msr = make_XRPEndpointStep(ctx(), next->getAccountID()); - if (!isTesSuccess(msr.first)) - return {msr.first, Strand{}}; - result.push_back(std::move(msr.second)); - } + + // Last step. insert xrp endpoint step + auto msr = make_XRPEndpointStep(ctx(), next->getAccountID()); + if (!isTesSuccess(msr.first)) + return {msr.first, Strand{}}; + result.push_back(std::move(msr.second)); } else { @@ -347,7 +349,9 @@ toStrand( auto s = toStep(ctx(/*isLast*/ i == normPath.size() - 2), cur, next, curIssue); if (isTesSuccess(s.first)) + { result.emplace_back(std::move(s.second)); + } else { JLOG(j.debug()) << "toStep failed: " << s.first; diff --git a/src/xrpld/app/rdb/backend/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/Node.cpp index eccc946e9f..09b4ebc241 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/Node.cpp @@ -97,8 +97,8 @@ makeLedgerDBs( return {std::move(lgr), std::move(tx), true}; } - else - return {std::move(lgr), {}, true}; + + return {std::move(lgr), {}, true}; } std::optional @@ -282,7 +282,9 @@ saveValidatedLedger( for (auto const& account : accts) { if (!first) + { sql += ", ('"; + } else { sql += "('"; @@ -600,9 +602,13 @@ getTxHistory(soci::session& session, Application& app, LedgerIndex startIndex, i while (st.fetch()) { if (soci::i_ok == rti) + { convert(sociRawTxnBlob, rawTxn); + } else + { rawTxn.clear(); + } if (auto trans = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app)) { @@ -665,8 +671,8 @@ transactionsSQL( numberOfResults = options.limit; } - std::string maxClause = ""; - std::string minClause = ""; + std::string maxClause; + std::string minClause; if (options.maxLedger) { @@ -683,13 +689,16 @@ transactionsSQL( std::string sql; if (count) + { sql = boost::str( boost::format( "SELECT %s FROM AccountTransactions " "WHERE Account = '%s' %s %s LIMIT %u, %u;") % selection % toBase58(options.account) % maxClause % minClause % options.offset % numberOfResults); + } else + { sql = boost::str( boost::format( "SELECT %s FROM " @@ -702,6 +711,7 @@ transactionsSQL( selection % toBase58(options.account) % maxClause % minClause % (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") % options.offset % numberOfResults); + } JLOG(j.trace()) << "txSQL query: " << sql; return sql; } @@ -746,7 +756,7 @@ getAccountTxs( false, false, j); - if (sql == "") + if (sql.empty()) return {ret, 0}; int total = 0; @@ -769,14 +779,22 @@ getAccountTxs( while (st.fetch()) { if (soci::i_ok == rti) + { convert(sociTxnBlob, rawTxn); + } else + { rawTxn.clear(); + } if (soci::i_ok == tmi) + { convert(sociTxnMetaBlob, txnMeta); + } else + { txnMeta.clear(); + } auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app); @@ -862,7 +880,7 @@ getAccountTxsB( true /*binary*/, false, j); - if (sql == "") + if (sql.empty()) return {ret, 0}; int total = 0; @@ -957,9 +975,13 @@ accountTxPage( if (options.limit == 0 || options.limit == UINT32_MAX || (options.limit > page_length && !options.bAdmin)) + { numberOfResults = page_length; + } else + { numberOfResults = options.limit; + } // As an account can have many thousands of transactions, there is a limit // placed on the amount of transactions returned. If the limit is reached @@ -1062,7 +1084,9 @@ accountTxPage( lookingForMarker = false; } else + { continue; + } } else if (numberOfResults == 0) { @@ -1072,17 +1096,25 @@ accountTxPage( } if (dataPresent == soci::i_ok) + { convert(txnData, rawData); + } else + { rawData.clear(); + } if (metaPresent == soci::i_ok) + { convert(txnMeta, rawMeta); + } else + { rawMeta.clear(); + } // Work around a bug that could leave the metadata missing - if (rawMeta.size() == 0) + if (rawMeta.empty()) onUnsavedLedger(ledgerSeq.value_or(0)); // `rawData` and `rawMeta` will be used after they are moved. diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index cee1ce5ed1..52186ca9da 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -154,7 +154,7 @@ parseIniFile(std::string const& strInput, bool const bTrim) boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of("\n")); // Set the default Section name. - std::string strSection = SECTION_DEFAULT_NAME; + std::string strSection = SECTION_DEFAULT_NAME; // NOLINT(readability-redundant-string-init) // Initialize the default Section. secResult[strSection] = IniFileSections::mapped_type(); @@ -364,9 +364,13 @@ Config::setup(std::string const& strConf, bool bQuiet, bool bSilent, bool bStand // load() may have set a new value for the dataDir std::string const dbPath(legacy("database_path")); if (!dbPath.empty()) + { dataDir = boost::filesystem::path(dbPath); + } else if (RUN_STANDALONE) + { dataDir.clear(); + } } if (!dataDir.empty()) @@ -493,13 +497,21 @@ Config::loadFromString(std::string const& fileContents) if (getSingleSection(secConfig, SECTION_NETWORK_ID, strTemp, j_)) { if (strTemp == "main") + { NETWORK_ID = 0; + } else if (strTemp == "testnet") + { NETWORK_ID = 1; + } else if (strTemp == "devnet") + { NETWORK_ID = 2; + } else + { NETWORK_ID = beast::lexicalCastThrow(strTemp); + } } if (getSingleSection(secConfig, SECTION_PEER_PRIVATE, strTemp, j_)) @@ -516,8 +528,10 @@ Config::loadFromString(std::string const& fileContents) { peers_in_max = beast::lexicalCastThrow(strTemp); if (*peers_in_max > 1000) + { Throw("Invalid value specified in [" SECTION_PEERS_IN_MAX "] section; the value must be less or equal than 1000"); + } } std::optional peers_out_max{}; @@ -525,15 +539,19 @@ Config::loadFromString(std::string const& fileContents) { peers_out_max = beast::lexicalCastThrow(strTemp); if (*peers_out_max < 10 || *peers_out_max > 1000) + { Throw("Invalid value specified in [" SECTION_PEERS_OUT_MAX "] section; the value must be in range 10-1000"); + } } // if one section is configured then the other must be configured too if ((peers_in_max && !peers_out_max) || (peers_out_max && !peers_in_max)) + { Throw("Both sections [" SECTION_PEERS_IN_MAX "]" "and [" SECTION_PEERS_OUT_MAX "] must be configured"); + } if (peers_in_max && peers_out_max) { @@ -545,17 +563,29 @@ Config::loadFromString(std::string const& fileContents) if (getSingleSection(secConfig, SECTION_NODE_SIZE, strTemp, j_)) { if (boost::iequals(strTemp, "tiny")) + { NODE_SIZE = 0; + } else if (boost::iequals(strTemp, "small")) + { NODE_SIZE = 1; + } else if (boost::iequals(strTemp, "medium")) + { NODE_SIZE = 2; + } else if (boost::iequals(strTemp, "large")) + { NODE_SIZE = 3; + } else if (boost::iequals(strTemp, "huge")) + { NODE_SIZE = 4; + } else + { NODE_SIZE = std::min(4, beast::lexicalCastThrow(strTemp)); + } } if (getSingleSection(secConfig, SECTION_SIGNING_SUPPORT, strTemp, j_)) @@ -573,32 +603,50 @@ Config::loadFromString(std::string const& fileContents) if (getSingleSection(secConfig, SECTION_RELAY_VALIDATIONS, strTemp, j_)) { if (boost::iequals(strTemp, "all")) + { RELAY_UNTRUSTED_VALIDATIONS = 1; + } else if (boost::iequals(strTemp, "trusted")) + { RELAY_UNTRUSTED_VALIDATIONS = 0; + } else if (boost::iequals(strTemp, "drop_untrusted")) + { RELAY_UNTRUSTED_VALIDATIONS = -1; + } else + { Throw("Invalid value specified in [" SECTION_RELAY_VALIDATIONS "] section"); + } } if (getSingleSection(secConfig, SECTION_RELAY_PROPOSALS, strTemp, j_)) { if (boost::iequals(strTemp, "all")) + { RELAY_UNTRUSTED_PROPOSALS = 1; + } else if (boost::iequals(strTemp, "trusted")) + { RELAY_UNTRUSTED_PROPOSALS = 0; + } else if (boost::iequals(strTemp, "drop_untrusted")) + { RELAY_UNTRUSTED_PROPOSALS = -1; + } else + { Throw("Invalid value specified in [" SECTION_RELAY_PROPOSALS "] section"); + } } if (exists(SECTION_VALIDATION_SEED) && exists(SECTION_VALIDATOR_TOKEN)) + { Throw("Cannot have both [" SECTION_VALIDATION_SEED "] and [" SECTION_VALIDATOR_TOKEN "] config sections"); + } if (getSingleSection(secConfig, SECTION_NETWORK_QUORUM, strTemp, j_)) NETWORK_QUORUM = beast::lexicalCastThrow(strTemp); @@ -613,24 +661,35 @@ Config::loadFromString(std::string const& fileContents) if (getSingleSection(secConfig, SECTION_LEDGER_HISTORY, strTemp, j_)) { if (boost::iequals(strTemp, "full")) + { LEDGER_HISTORY = std::numeric_limits::max(); + } else if (boost::iequals(strTemp, "none")) + { LEDGER_HISTORY = 0; + } else + { LEDGER_HISTORY = beast::lexicalCastThrow(strTemp); + } } if (getSingleSection(secConfig, SECTION_FETCH_DEPTH, strTemp, j_)) { if (boost::iequals(strTemp, "none")) + { FETCH_DEPTH = 0; + } else if (boost::iequals(strTemp, "full")) + { FETCH_DEPTH = std::numeric_limits::max(); + } else + { FETCH_DEPTH = beast::lexicalCastThrow(strTemp); + } - if (FETCH_DEPTH < 10) - FETCH_DEPTH = 10; + FETCH_DEPTH = std::max(FETCH_DEPTH, 10); } // By default, validators don't have pathfinding enabled, unless it is @@ -655,8 +714,10 @@ Config::loadFromString(std::string const& fileContents) SWEEP_INTERVAL = beast::lexicalCastThrow(strTemp); if (SWEEP_INTERVAL < 10 || SWEEP_INTERVAL > 600) + { Throw("Invalid " SECTION_SWEEP_INTERVAL ": must be between 10 and 600 inclusive"); + } } if (getSingleSection(secConfig, SECTION_WORKERS, strTemp, j_)) @@ -664,8 +725,10 @@ Config::loadFromString(std::string const& fileContents) WORKERS = beast::lexicalCastThrow(strTemp); if (WORKERS < 1 || WORKERS > 1024) + { Throw("Invalid " SECTION_WORKERS ": must be between 1 and 1024 inclusive."); + } } if (getSingleSection(secConfig, SECTION_IO_WORKERS, strTemp, j_)) @@ -673,8 +736,10 @@ Config::loadFromString(std::string const& fileContents) IO_WORKERS = beast::lexicalCastThrow(strTemp); if (IO_WORKERS < 1 || IO_WORKERS > 1024) + { Throw("Invalid " SECTION_IO_WORKERS ": must be between 1 and 1024 inclusive."); + } } if (getSingleSection(secConfig, SECTION_PREFETCH_WORKERS, strTemp, j_)) @@ -682,8 +747,10 @@ Config::loadFromString(std::string const& fileContents) PREFETCH_WORKERS = beast::lexicalCastThrow(strTemp); if (PREFETCH_WORKERS < 1 || PREFETCH_WORKERS > 1024) + { Throw("Invalid " SECTION_PREFETCH_WORKERS ": must be between 1 and 1024 inclusive."); + } } if (getSingleSection(secConfig, SECTION_COMPRESSION, strTemp, j_)) @@ -703,18 +770,26 @@ Config::loadFromString(std::string const& fileContents) // VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = // // sec.value_or("vp_base_squelch_enable", true); // if (sec.exists("vp_base_squelch_enable") && sec.exists("vp_enable")) + { Throw("Invalid " SECTION_REDUCE_RELAY " cannot specify both vp_base_squelch_enable and vp_enable " "options. " "vp_enable was deprecated and replaced by " "vp_base_squelch_enable"); + } if (sec.exists("vp_base_squelch_enable")) + { VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = sec.value_or("vp_base_squelch_enable", false); + } else if (sec.exists("vp_enable")) + { VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = sec.value_or("vp_enable", false); + } else + { VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = false; + } ///////////////// !!END OF TEMPORARY CODE BLOCK!! ///////////////////// ///////////////////// !!TEMPORARY CODE BLOCK!! /////////////////////// @@ -724,9 +799,11 @@ Config::loadFromString(std::string const& fileContents) VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = sec.value_or("vp_base_squelch_max_selected_peers", 5); if (VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS < 3) + { Throw("Invalid " SECTION_REDUCE_RELAY " vp_base_squelch_max_selected_peers must be " "greater than or equal to 3"); + } ///////////////// !!END OF TEMPORARY CODE BLOCK!! ///////////////////// TX_REDUCE_RELAY_ENABLE = sec.value_or("tx_enable", false); @@ -734,10 +811,12 @@ Config::loadFromString(std::string const& fileContents) TX_REDUCE_RELAY_MIN_PEERS = sec.value_or("tx_min_peers", 20); TX_RELAY_PERCENTAGE = sec.value_or("tx_relay_percentage", 25); if (TX_RELAY_PERCENTAGE < 10 || TX_RELAY_PERCENTAGE > 100 || TX_REDUCE_RELAY_MIN_PEERS < 10) + { Throw("Invalid " SECTION_REDUCE_RELAY ", tx_min_peers must be greater than or equal to 10" ", tx_relay_percentage must be greater than or equal to 10 " "and less than or equal to 100"); + } } if (getSingleSection(secConfig, SECTION_MAX_TRANSACTIONS, strTemp, j_)) @@ -776,9 +855,11 @@ Config::loadFromString(std::string const& fileContents) } if (MAX_UNKNOWN_TIME < seconds{300} || MAX_UNKNOWN_TIME > seconds{1800}) + { Throw( "Invalid value 'max_unknown_time' in " SECTION_OVERLAY ": the time must be between 300 and 1800 seconds, inclusive."); + } try { @@ -804,24 +885,36 @@ Config::loadFromString(std::string const& fileContents) boost::regex const re("^\\s*(\\d+)\\s*(minutes|hours|days|weeks)\\s*(\\s+.*)?$"); boost::smatch match; if (!boost::regex_match(strTemp, match, re)) + { Throw("Invalid " SECTION_AMENDMENT_MAJORITY_TIME ", must be: [0-9]+ [minutes|hours|days|weeks]"); + } std::uint32_t duration = beast::lexicalCastThrow(match[1].str()); if (boost::iequals(match[2], "minutes")) + { AMENDMENT_MAJORITY_TIME = minutes(duration); + } else if (boost::iequals(match[2], "hours")) + { AMENDMENT_MAJORITY_TIME = hours(duration); + } else if (boost::iequals(match[2], "days")) + { AMENDMENT_MAJORITY_TIME = days(duration); + } else if (boost::iequals(match[2], "weeks")) + { AMENDMENT_MAJORITY_TIME = weeks(duration); + } if (AMENDMENT_MAJORITY_TIME < minutes(15)) + { Throw("Invalid " SECTION_AMENDMENT_MAJORITY_TIME ", the minimum amount of time an amendment must hold a " "majority is 15 minutes"); + } } if (getSingleSection(secConfig, SECTION_BETA_RPC_API, strTemp, j_)) @@ -845,25 +938,30 @@ Config::loadFromString(std::string const& fileContents) validatorsFile = strTemp; if (validatorsFile.empty()) + { Throw("Invalid path specified in [" SECTION_VALIDATORS_FILE "]"); + } if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty()) validatorsFile = CONFIG_DIR / validatorsFile; if (!boost::filesystem::exists(validatorsFile)) + { Throw( "The file specified in [" SECTION_VALIDATORS_FILE "] " "does not exist: " + validatorsFile.string()); - + } else if ( !boost::filesystem::is_regular_file(validatorsFile) && !boost::filesystem::is_symlink(validatorsFile)) + { Throw( "Invalid file specified in [" SECTION_VALIDATORS_FILE "]: " + validatorsFile.string()); + } } else if (!CONFIG_DIR.empty()) { @@ -872,11 +970,15 @@ Config::loadFromString(std::string const& fileContents) if (!validatorsFile.empty()) { if (!boost::filesystem::exists(validatorsFile)) + { validatorsFile.clear(); + } else if ( !boost::filesystem::is_regular_file(validatorsFile) && !boost::filesystem::is_symlink(validatorsFile)) + { validatorsFile.clear(); + } } } @@ -921,6 +1023,7 @@ Config::loadFromString(std::string const& fileContents) section(SECTION_VALIDATOR_LIST_THRESHOLD).append(*valListThreshold); if (!entries && !valKeyEntries && !valListKeys) + { Throw( "The file specified in [" SECTION_VALIDATORS_FILE "] " @@ -932,19 +1035,24 @@ Config::loadFromString(std::string const& fileContents) "]" " section: " + validatorsFile.string()); + } } VALIDATOR_LIST_THRESHOLD = [&]() -> std::optional { auto const& listThreshold = section(SECTION_VALIDATOR_LIST_THRESHOLD); if (listThreshold.lines().empty()) + { return std::nullopt; - else if (listThreshold.values().size() == 1) + } + if (listThreshold.values().size() == 1) { auto strTemp = listThreshold.values()[0]; auto const listThreshold = beast::lexicalCastThrow(strTemp); if (listThreshold == 0) + { return std::nullopt; // NOTE: Explicitly ask for computed - else if (listThreshold > section(SECTION_VALIDATOR_LIST_KEYS).values().size()) + } + if (listThreshold > section(SECTION_VALIDATOR_LIST_KEYS).values().size()) { Throw( "Value in config section " @@ -953,12 +1061,10 @@ Config::loadFromString(std::string const& fileContents) } return listThreshold; } - else - { - Throw( - "Config section " - "[" SECTION_VALIDATOR_LIST_THRESHOLD "] should contain single value only"); - } + + Throw( + "Config section " + "[" SECTION_VALIDATOR_LIST_THRESHOLD "] should contain single value only"); }(); // Consolidate [validator_keys] and [validators] @@ -977,9 +1083,13 @@ Config::loadFromString(std::string const& fileContents) for (auto const& s : part.values()) { if (auto const f = getRegisteredFeature(s)) + { features.insert(*f); + } else + { Throw("Unknown feature: " + s + " in config file."); + } } } diff --git a/src/xrpld/overlay/detail/ConnectAttempt.cpp b/src/xrpld/overlay/detail/ConnectAttempt.cpp index 54765c68db..78aee006f1 100644 --- a/src/xrpld/overlay/detail/ConnectAttempt.cpp +++ b/src/xrpld/overlay/detail/ConnectAttempt.cpp @@ -51,7 +51,10 @@ void ConnectAttempt::stop() { if (!strand_.running_in_this_thread()) - return boost::asio::post(strand_, std::bind(&ConnectAttempt::stop, shared_from_this())); + { + boost::asio::post(strand_, std::bind(&ConnectAttempt::stop, shared_from_this())); + return; + } if (!socket_.is_open()) return; @@ -65,7 +68,10 @@ void ConnectAttempt::run() { if (!strand_.running_in_this_thread()) - return boost::asio::post(strand_, std::bind(&ConnectAttempt::run, shared_from_this())); + { + boost::asio::post(strand_, std::bind(&ConnectAttempt::run, shared_from_this())); + return; + } JLOG(journal_.debug()) << "run: connecting to " << remote_endpoint_; @@ -115,9 +121,10 @@ ConnectAttempt::tryAsyncShutdown() if (currentStep_ != ConnectionStep::TcpConnect && currentStep_ != ConnectionStep::TlsHandshake) { setTimer(ConnectionStep::ShutdownStarted); - return stream_.async_shutdown(bind_executor( + stream_.async_shutdown(bind_executor( strand_, std::bind(&ConnectAttempt::onShutdown, shared_from_this(), std::placeholders::_1))); + return; } close(); @@ -197,7 +204,8 @@ ConnectAttempt::setTimer(ConnectionStep step) catch (std::exception const& ex) { JLOG(journal_.error()) << "setTimer (global): " << ex.what(); - return close(); + close(); + return; } } @@ -240,7 +248,8 @@ ConnectAttempt::setTimer(ConnectionStep step) catch (std::exception const& ex) { JLOG(journal_.error()) << "setTimer (step " << stepToString(step) << "): " << ex.what(); - return close(); + close(); + return; } } @@ -272,7 +281,8 @@ ConnectAttempt::onTimer(error_code ec) // This should never happen JLOG(journal_.error()) << "onTimer: " << ec.message(); - return close(); + close(); + return; } // Determine which timer expired by checking their expiry times @@ -304,9 +314,13 @@ ConnectAttempt::onConnect(error_code ec) if (ec) { if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } - return fail("onConnect", ec); + fail("onConnect", ec); + return; } if (!socket_.is_open()) @@ -315,10 +329,16 @@ ConnectAttempt::onConnect(error_code ec) // check if connection has really been established socket_.local_endpoint(ec); if (ec) - return fail("onConnect", ec); + { + fail("onConnect", ec); + return; + } if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } ioPending_ = true; @@ -340,25 +360,38 @@ ConnectAttempt::onHandshake(error_code ec) if (ec) { if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } - return fail("onHandshake", ec); + fail("onHandshake", ec); + return; } auto const local_endpoint = socket_.local_endpoint(ec); if (ec) - return fail("onHandshake", ec); + { + fail("onHandshake", ec); + return; + } setTimer(ConnectionStep::HttpWrite); // check if we connected to ourselves if (!overlay_.peerFinder().onConnected( slot_, beast::IPAddressConversion::from_asio(local_endpoint))) - return fail("Self connection"); + { + fail("Self connection"); + return; + } auto const sharedValue = makeSharedValue(*stream_ptr_, journal_); if (!sharedValue) - return shutdown(); // makeSharedValue logs + { + shutdown(); + return; // makeSharedValue logs + } req_ = makeRequest( !overlay_.peerFinder().config().peerPrivate, @@ -376,7 +409,10 @@ ConnectAttempt::onHandshake(error_code ec) app_); if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } ioPending_ = true; @@ -396,13 +432,20 @@ ConnectAttempt::onWrite(error_code ec) if (ec) { if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } - return fail("onWrite", ec); + fail("onWrite", ec); + return; } if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } ioPending_ = true; @@ -429,17 +472,25 @@ ConnectAttempt::onRead(error_code ec) if (ec == boost::asio::error::eof) { JLOG(journal_.debug()) << "EOF"; - return shutdown(); + shutdown(); + return; } if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } - return fail("onRead", ec); + fail("onRead", ec); + return; } if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } processResponse(); } @@ -457,7 +508,8 @@ ConnectAttempt::processResponse() { JLOG(journal_.warn()) << "Unable to upgrade to peer protocol: " << response_.result() << " (" << response_.reason() << ")"; - return shutdown(); + shutdown(); + return; } // Parse response body to determine if this is a redirect or other @@ -465,8 +517,10 @@ ConnectAttempt::processResponse() std::string responseBody; responseBody.reserve(boost::asio::buffer_size(response_.body().data())); for (auto const buffer : response_.body().data()) + { responseBody.append( static_cast(buffer.data()), boost::asio::buffer_size(buffer)); + } Json::Value json; Json::Reader reader; @@ -481,12 +535,16 @@ ConnectAttempt::processResponse() << " failed to upgrade to peer protocol: " << response_.result() << " (" << response_.reason() << ")"; - return shutdown(); + shutdown(); + return; } Json::Value const& peerIps = json["peer-ips"]; if (!peerIps.isArray()) - return fail("processResponse: invalid peer-ips format"); + { + fail("processResponse: invalid peer-ips format"); + return; + } // Extract and validate peer endpoints std::vector redirectEndpoints; @@ -506,7 +564,8 @@ ConnectAttempt::processResponse() // Notify PeerFinder about the redirect redirectEndpoints may be empty overlay_.peerFinder().onRedirects(remote_endpoint_, redirectEndpoints); - return fail("processResponse: failed to connect to peer: redirected"); + fail("processResponse: failed to connect to peer: redirected"); + return; } // Just because our peer selected a particular protocol version doesn't @@ -520,12 +579,18 @@ ConnectAttempt::processResponse() negotiatedProtocol = pvs[0]; if (!negotiatedProtocol) - return fail("processResponse: Unable to negotiate protocol version"); + { + fail("processResponse: Unable to negotiate protocol version"); + return; + } } auto const sharedValue = makeSharedValue(*stream_ptr_, journal_); if (!sharedValue) - return shutdown(); // makeSharedValue logs + { + shutdown(); + return; // makeSharedValue logs + } try { @@ -553,14 +618,18 @@ ConnectAttempt::processResponse() { std::stringstream ss; ss << "Outbound Connect Attempt " << remote_endpoint_ << " " << to_string(result); - return fail(ss.str()); + fail(ss.str()); + return; } if (!socket_.is_open()) return; if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } auto const peer = std::make_shared( app_, @@ -578,7 +647,8 @@ ConnectAttempt::processResponse() } catch (std::exception const& e) { - return fail(std::string("Handshake failure (") + e.what() + ")"); + fail(std::string("Handshake failure (") + e.what() + ")"); + return; } } diff --git a/src/xrpld/overlay/detail/Handshake.cpp b/src/xrpld/overlay/detail/Handshake.cpp index 715afc90e8..e9ad25bcc4 100644 --- a/src/xrpld/overlay/detail/Handshake.cpp +++ b/src/xrpld/overlay/detail/Handshake.cpp @@ -300,9 +300,11 @@ verifyHandshake( throw std::runtime_error("Invalid Local-IP"); if (beast::IP::is_public(remote) && remote != local_ip) + { throw std::runtime_error( "Incorrect Local-IP: " + remote.to_string() + " instead of " + local_ip.to_string()); + } } if (auto const iter = headers.find("Remote-IP"); iter != headers.end()) @@ -318,9 +320,11 @@ verifyHandshake( // We know our public IP and peer reports our connection came // from some other IP. if (remote_ip != public_ip) + { throw std::runtime_error( "Incorrect Remote-IP: " + public_ip.to_string() + " instead of " + remote_ip.to_string()); + } } } diff --git a/src/xrpld/overlay/detail/Message.cpp b/src/xrpld/overlay/detail/Message.cpp index 672ce995ca..754545f04a 100644 --- a/src/xrpld/overlay/detail/Message.cpp +++ b/src/xrpld/overlay/detail/Message.cpp @@ -106,7 +106,9 @@ Message::compress() setHeader(bufferCompressed_.data(), compressedSize, type, Algorithm::LZ4, messageBytes); } else + { bufferCompressed_.resize(0); + } } } @@ -188,10 +190,12 @@ Message::getBuffer(Compressed tryCompressed) std::call_once(once_flag_, &Message::compress, this); - if (bufferCompressed_.size() > 0) + if (!bufferCompressed_.empty()) + { return bufferCompressed_; - else - return buffer_; + } + + return buffer_; } int diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index d9680d7748..d9077686ec 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -24,6 +24,8 @@ #include #include +#include + namespace xrpl { namespace CrawlOptions { @@ -479,9 +481,13 @@ OverlayImpl::start() for (auto const& addr : addresses) { if (addr.port() == 0) + { ips.push_back(to_string(addr.at_port(DEFAULT_PEER_PORT))); + } else + { ips.push_back(to_string(addr)); + } } std::string const base("config: "); @@ -501,9 +507,13 @@ OverlayImpl::start() for (auto& addr : addresses) { if (addr.port() == 0) + { ips.emplace_back(addr.address(), DEFAULT_PEER_PORT); + } else + { ips.emplace_back(addr); + } } if (!ips.empty()) @@ -634,8 +644,10 @@ OverlayImpl::onManifests( } if (!relay.list().empty()) + { for_each([m2 = std::make_shared(relay, protocol::mtMANIFESTS)]( std::shared_ptr const& p) { p->send(m2); }); + } } void @@ -667,7 +679,7 @@ OverlayImpl::limit() } Json::Value -OverlayImpl::getOverlayInfo() +OverlayImpl::getOverlayInfo() const { using namespace std::chrono; Json::Value jv; @@ -695,8 +707,10 @@ OverlayImpl::getOverlayInfo() { auto version{sp->getVersion()}; if (!version.empty()) + { // Could move here if Json::value supported moving from strings pv[jss::version] = std::string{version}; + } } std::uint32_t minSeq = 0, maxSeq = 0; @@ -868,20 +882,18 @@ OverlayImpl::processValidatorList(http_request_type const& req, Handoff& handoff // 404 not found return fail(boost::beast::http::status::not_found); } - else if (!*vl) + if (!*vl) { return fail(boost::beast::http::status::bad_request); } - else - { - msg.result(boost::beast::http::status::ok); - msg.body() = *vl; + msg.result(boost::beast::http::status::ok); - msg.prepare_payload(); - handoff.response = std::make_shared(msg); - return true; - } + msg.body() = *vl; + + msg.prepare_payload(); + handoff.response = std::make_shared(msg); + return true; } bool @@ -909,19 +921,20 @@ OverlayImpl::processHealth(http_request_type const& req, Handoff& handoff) enum class HealthState { healthy, warning, critical }; auto health = HealthState::healthy; - auto set_health = [&health](HealthState state) { - if (health < state) - health = state; - }; + auto set_health = [&health](HealthState state) { health = std::max(health, state); }; msg.body()[jss::info] = Json::objectValue; if (last_validated_ledger_age >= 7 || last_validated_ledger_age < 0) { msg.body()[jss::info][jss::validated_ledger] = last_validated_ledger_age; if (last_validated_ledger_age < 20) + { set_health(HealthState::warning); + } else + { set_health(HealthState::critical); + } } if (amendment_blocked) @@ -934,9 +947,13 @@ OverlayImpl::processHealth(http_request_type const& req, Handoff& handoff) { msg.body()[jss::info][jss::peers] = number_peers; if (number_peers != 0) + { set_health(HealthState::warning); + } else + { set_health(HealthState::critical); + } } if (!(server_state == "full" || server_state == "validating" || server_state == "proposing")) @@ -947,16 +964,22 @@ OverlayImpl::processHealth(http_request_type const& req, Handoff& handoff) set_health(HealthState::warning); } else + { set_health(HealthState::critical); + } } if (load_factor > 100) { msg.body()[jss::info][jss::load_factor] = load_factor; if (load_factor < 1000) + { set_health(HealthState::warning); + } else + { set_health(HealthState::critical); + } } switch (health) @@ -1021,10 +1044,14 @@ OverlayImpl::getActivePeers( if (!reduceRelayEnabled) ++disabled; - if (toSkip.count(id) == 0) + if (!toSkip.contains(id)) + { ret.emplace_back(std::move(p)); + } else if (reduceRelayEnabled) + { ++enabledInSkip; + } } } @@ -1080,7 +1107,7 @@ OverlayImpl::relay(protocol::TMProposeSet& m, uint256 const& uid, PublicKey cons { auto const sm = std::make_shared(m, protocol::mtPROPOSE_LEDGER, validator); for_each([&](std::shared_ptr const& p) { - if (toSkip->find(p->id()) == toSkip->end()) + if (!toSkip->contains(p->id())) p->send(sm); }); return *toSkip; @@ -1102,7 +1129,7 @@ OverlayImpl::relay(protocol::TMValidation& m, uint256 const& uid, PublicKey cons { auto const sm = std::make_shared(m, protocol::mtVALIDATION, validator); for_each([&](std::shared_ptr const& p) { - if (toSkip->find(p->id()) == toSkip->end()) + if (!toSkip->contains(p->id())) p->send(sm); }); return *toSkip; @@ -1297,7 +1324,7 @@ OverlayImpl::sendEndpoints() } void -OverlayImpl::sendTxQueue() +OverlayImpl::sendTxQueue() const { for_each([](auto const& p) { if (p->txReduceRelayEnabled()) @@ -1347,17 +1374,23 @@ OverlayImpl::updateSlotAndSquelch( return; if (!strand_.running_in_this_thread()) - return post( + { + post( strand_, // Must capture copies of reference parameters (i.e. key, validator) [this, key = key, validator = validator, peers = std::move(peers), type]() mutable { updateSlotAndSquelch(key, validator, std::move(peers), type); }); + return; + } + for (auto id : peers) + { slots_.updateSlotAndSquelch(key, validator, id, type, [&]() { reportInboundTraffic(TrafficCount::squelch_ignored, 0); }); + } } void @@ -1371,12 +1404,17 @@ OverlayImpl::updateSlotAndSquelch( return; if (!strand_.running_in_this_thread()) - return post( - strand_, - // Must capture copies of reference parameters (i.e. key, validator) - [this, key = key, validator = validator, peer, type]() { - updateSlotAndSquelch(key, validator, peer, type); - }); + { + { + post( + strand_, + // Must capture copies of reference parameters (i.e. key, validator) + [this, key = key, validator = validator, peer, type]() { + updateSlotAndSquelch(key, validator, peer, type); + }); + } + return; + } slots_.updateSlotAndSquelch(key, validator, peer, type, [&]() { reportInboundTraffic(TrafficCount::squelch_ignored, 0); @@ -1387,7 +1425,10 @@ void OverlayImpl::deletePeer(Peer::id_t id) { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&OverlayImpl::deletePeer, this, id)); + { + post(strand_, std::bind(&OverlayImpl::deletePeer, this, id)); + return; + } slots_.deletePeer(id, true); } @@ -1396,7 +1437,10 @@ void OverlayImpl::deleteIdlePeers() { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&OverlayImpl::deleteIdlePeers, this)); + { + post(strand_, std::bind(&OverlayImpl::deleteIdlePeers, this)); + return; + } slots_.deleteIdlePeers(); } diff --git a/src/xrpld/overlay/detail/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h index 9e891e6e8a..b77b4e69aa 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.h +++ b/src/xrpld/overlay/detail/OverlayImpl.h @@ -474,7 +474,7 @@ private: Controlled through the config section [crawl] overlay=[0|1] */ Json::Value - getOverlayInfo(); + getOverlayInfo() const; /** Returns information about the local server. Reported through the /crawl API @@ -522,7 +522,7 @@ private: /** Send once a second transactions' hashes aggregated by peers. */ void - sendTxQueue(); + sendTxQueue() const; /** Check if peers stopped relaying messages * and if slots stopped receiving messages from the validator */ diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 18e784cdeb..7ed8c45453 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -134,7 +134,10 @@ void PeerImp::run() { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&PeerImp::run, shared_from_this())); + { + post(strand_, std::bind(&PeerImp::run, shared_from_this())); + return; + } auto parseLedgerHash = [](std::string_view value) -> std::optional { if (uint256 ret; ret.parseHex(value)) @@ -177,9 +180,13 @@ PeerImp::run() } if (inbound_) + { doAccept(); + } else + { doProtocolStart(); + } // Anything else that needs to be done with the connection should be // done in doProtocolStart @@ -189,7 +196,10 @@ void PeerImp::stop() { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&PeerImp::stop, shared_from_this())); + { + post(strand_, std::bind(&PeerImp::stop, shared_from_this())); + return; + } if (!socket_.is_open()) return; @@ -209,14 +219,20 @@ void PeerImp::send(std::shared_ptr const& m) { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&PeerImp::send, shared_from_this(), m)); + { + post(strand_, std::bind(&PeerImp::send, shared_from_this(), m)); + return; + } if (!socket_.is_open()) return; // we are in progress of closing the connection if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } auto validator = m->getValidatorKey(); if (validator && !squelch_.expireSquelch(*validator)) @@ -273,7 +289,10 @@ void PeerImp::sendTxQueue() { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&PeerImp::sendTxQueue, shared_from_this())); + { + post(strand_, std::bind(&PeerImp::sendTxQueue, shared_from_this())); + return; + } if (!txQueue_.empty()) { @@ -291,7 +310,10 @@ void PeerImp::addTxQueue(uint256 const& hash) { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&PeerImp::addTxQueue, shared_from_this(), hash)); + { + post(strand_, std::bind(&PeerImp::addTxQueue, shared_from_this(), hash)); + return; + } if (txQueue_.size() == reduce_relay::MAX_TX_QUEUE_SIZE) { @@ -307,7 +329,10 @@ void PeerImp::removeTxQueue(uint256 const& hash) { if (!strand_.running_in_this_thread()) - return post(strand_, std::bind(&PeerImp::removeTxQueue, shared_from_this(), hash)); + { + post(strand_, std::bind(&PeerImp::removeTxQueue, shared_from_this(), hash)); + return; + } auto removed = txQueue_.erase(hash); JLOG(p_journal_.trace()) << "removeTxQueue " << removed; @@ -366,8 +391,10 @@ PeerImp::json() ret[jss::cluster] = true; if (auto const n = name(); !n.empty()) + { // Could move here if Json::Value supported moving from a string ret[jss::name] = n; + } } if (auto const d = domain(); !d.empty()) @@ -545,10 +572,13 @@ void PeerImp::fail(std::string const& reason) { if (!strand_.running_in_this_thread()) - return post( + { + post( strand_, std::bind( (void (Peer::*)(std::string const&))&PeerImp::fail, shared_from_this(), reason)); + return; + } if (!socket_.is_open()) return; @@ -658,7 +688,8 @@ PeerImp::setTimer(std::chrono::seconds interval) catch (std::exception const& ex) { JLOG(journal_.error()) << "setTimer: " << ex.what(); - return shutdown(); + shutdown(); + return; } timer_.async_wait(bind_executor( @@ -691,7 +722,8 @@ PeerImp::onTimer(error_code const& ec) // This should never happen JLOG(journal_.error()) << "onTimer: " << ec.message(); - return close(); + close(); + return; } // the timer expired before the shutdown completed @@ -699,11 +731,15 @@ PeerImp::onTimer(error_code const& ec) if (shutdown_) { JLOG(journal_.debug()) << "onTimer: shutdown timer expired"; - return close(); + close(); + return; } if (large_sendq_++ >= Tuning::sendqIntervals) - return fail("Large send queue"); + { + fail("Large send queue"); + return; + } if (auto const t = tracking_.load(); !inbound_ && t != Tracking::converged) { @@ -718,13 +754,17 @@ PeerImp::onTimer(error_code const& ec) (t == Tracking::unknown && (duration > app_.config().MAX_UNKNOWN_TIME))) { overlay_.peerFinder().on_failure(slot_); - return fail("Not useful"); + fail("Not useful"); + return; } } // Already waiting for PONG if (lastPingSeq_) - return fail("Ping Timeout"); + { + fail("Ping Timeout"); + return; + } lastPingTime_ = clock_type::now(); lastPingSeq_ = rand_int(); @@ -761,14 +801,20 @@ PeerImp::doAccept() // a shutdown was initiated before the handshake, there is nothing to do if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } auto const sharedValue = makeSharedValue(*stream_ptr_, journal_); // This shouldn't fail since we already computed // the shared value successfully in OverlayImpl if (!sharedValue) - return fail("makeSharedValue: Unexpected failure"); + { + fail("makeSharedValue: Unexpected failure"); + return; + } JLOG(journal_.debug()) << "Protocol: " << to_string(protocol_); @@ -811,12 +857,22 @@ PeerImp::doAccept() if (!socket_.is_open()) return; if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } if (ec) - return fail("onWriteResponse", ec); + { + fail("onWriteResponse", ec); + return; + } if (write_buffer->size() == bytes_transferred) - return doProtocolStart(); - return fail("Failed to write header"); + { + doProtocolStart(); + return; + } + fail("Failed to write header"); + return; })); } @@ -842,7 +898,10 @@ PeerImp::doProtocolStart() { // a shutdown was initiated before the handshare, there is nothing to do if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } onReadMessage(error_code(), 0); @@ -895,17 +954,25 @@ PeerImp::onReadMessage(error_code ec, std::size_t bytes_transferred) if (ec == boost::asio::error::eof) { JLOG(journal_.debug()) << "EOF"; - return shutdown(); + shutdown(); + return; } if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } - return fail("onReadMessage", ec); + fail("onReadMessage", ec); + return; } // we started shutdown, no reason to process further data if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } if (auto stream = journal_.trace()) { @@ -936,7 +1003,10 @@ PeerImp::onReadMessage(error_code ec, std::size_t bytes_transferred) // the error_code is produced by invokeProtocolMessage // it could be due to a bad message if (ec) - return fail("onReadMessage", ec); + { + fail("onReadMessage", ec); + return; + } if (bytes_consumed == 0) break; @@ -946,7 +1016,10 @@ PeerImp::onReadMessage(error_code ec, std::size_t bytes_transferred) // check if a shutdown was initiated while processing messages if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } readPending_ = true; @@ -978,9 +1051,13 @@ PeerImp::onWriteMessage(error_code ec, std::size_t bytes_transferred) if (ec) { if (ec == boost::asio::error::operation_aborted) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } - return fail("onWriteMessage", ec); + fail("onWriteMessage", ec); + return; } if (auto stream = journal_.trace()) @@ -995,7 +1072,10 @@ PeerImp::onWriteMessage(error_code ec, std::size_t bytes_transferred) send_queue_.pop(); if (shutdown_) - return tryAsyncShutdown(); + { + tryAsyncShutdown(); + return; + } if (!send_queue_.empty()) { @@ -1003,7 +1083,7 @@ PeerImp::onWriteMessage(error_code ec, std::size_t bytes_transferred) XRPL_ASSERT(!shutdownStarted_, "xrpl::PeerImp::onWriteMessage : shutdown started"); // Timeout on writes only - return boost::asio::async_write( + boost::asio::async_write( stream_, boost::asio::buffer(send_queue_.front()->getBuffer(compressionEnabled_)), bind_executor( @@ -1013,6 +1093,7 @@ PeerImp::onWriteMessage(error_code ec, std::size_t bytes_transferred) shared_from_this(), std::placeholders::_1, std::placeholders::_2))); + return; } } @@ -1122,9 +1203,13 @@ PeerImp::onMessage(std::shared_ptr const& m) std::lock_guard sl(recentLock_); if (latency_) + { latency_ = (*latency_ * 7 + rtt) / 8; + } else + { latency_ = rtt; + } } return; @@ -1330,7 +1415,9 @@ PeerImp::handleTransaction( // Erase only if the server has seen this tx. If the server has not // seen this tx then the tx could not has been queued for this peer. else if (eraseTxQueue && txReduceRelayEnabled()) + { removeTxQueue(txID); + } overlay_.reportInboundTraffic( TrafficCount::category::transaction_duplicate, Message::messageSize(*m)); @@ -1402,7 +1489,10 @@ PeerImp::onMessage(std::shared_ptr const& m) // Verify ledger info type if (itype < protocol::liBASE || itype > protocol::liTS_CANDIDATE) - return badData("Invalid ledger info type"); + { + badData("Invalid ledger info type"); + return; + } auto const ltype = [&m]() -> std::optional<::protocol::TMLedgerType> { if (m->has_ltype()) @@ -1413,21 +1503,31 @@ PeerImp::onMessage(std::shared_ptr const& m) if (itype == protocol::liTS_CANDIDATE) { if (!m->has_ledgerhash()) - return badData("Invalid TX candidate set, missing TX set hash"); + { + badData("Invalid TX candidate set, missing TX set hash"); + return; + } } else if ( !m->has_ledgerhash() && !m->has_ledgerseq() && !(ltype && *ltype == protocol::ltCLOSED)) { - return badData("Invalid request"); + badData("Invalid request"); + return; } // Verify ledger type if (ltype && (*ltype < protocol::ltACCEPTED || *ltype > protocol::ltCLOSED)) - return badData("Invalid ledger type"); + { + badData("Invalid ledger type"); + return; + } // Verify ledger hash if (m->has_ledgerhash() && !stringIsUint256Sized(m->ledgerhash())) - return badData("Invalid ledger hash"); + { + badData("Invalid ledger hash"); + return; + } // Verify ledger sequence if (m->has_ledgerseq()) @@ -1439,7 +1539,8 @@ PeerImp::onMessage(std::shared_ptr const& m) if (app_.getLedgerMaster().getValidatedLedgerAge() <= 10s && ledgerSeq > app_.getLedgerMaster().getValidLedgerIndex() + 10) { - return badData("Invalid ledger sequence " + std::to_string(ledgerSeq)); + badData("Invalid ledger sequence " + std::to_string(ledgerSeq)); + return; } } @@ -1447,25 +1548,35 @@ PeerImp::onMessage(std::shared_ptr const& m) if (itype != protocol::liBASE) { if (m->nodeids_size() <= 0) - return badData("Invalid ledger node IDs"); + { + badData("Invalid ledger node IDs"); + return; + } for (auto const& nodeId : m->nodeids()) { if (deserializeSHAMapNodeID(nodeId) == std::nullopt) - return badData("Invalid SHAMap node ID"); + { + badData("Invalid SHAMap node ID"); + return; + } } } // Verify query type if (m->has_querytype() && m->querytype() != protocol::qtINDIRECT) - return badData("Invalid query type"); + { + badData("Invalid query type"); + return; + } // Verify query depth if (m->has_querydepth()) { if (m->querydepth() > Tuning::maxQueryDepth || itype == protocol::liBASE) { - return badData("Invalid query depth"); + badData("Invalid query depth"); + return; } } @@ -1496,9 +1607,13 @@ PeerImp::onMessage(std::shared_ptr const& m) if (reply.has_error()) { if (reply.error() == protocol::TMReplyError::reBAD_REQUEST) + { peer->charge(Resource::feeMalformedRequest, "proof_path_request"); + } else + { peer->charge(Resource::feeRequestNoReply, "proof_path_request"); + } } else { @@ -1542,9 +1657,13 @@ PeerImp::onMessage(std::shared_ptr const& m) if (reply.has_error()) { if (reply.error() == protocol::TMReplyError::reBAD_REQUEST) + { peer->charge(Resource::feeMalformedRequest, "replay_delta_request"); + } else + { peer->charge(Resource::feeRequestNoReply, "replay_delta_request"); + } } else { @@ -1579,7 +1698,10 @@ PeerImp::onMessage(std::shared_ptr const& m) // Verify ledger hash if (!stringIsUint256Sized(m->ledgerhash())) - return badData("Invalid ledger hash"); + { + badData("Invalid ledger hash"); + return; + } // Verify ledger sequence { @@ -1588,7 +1710,8 @@ PeerImp::onMessage(std::shared_ptr const& m) { if (ledgerSeq != 0) { - return badData("Invalid ledger sequence " + std::to_string(ledgerSeq)); + badData("Invalid ledger sequence " + std::to_string(ledgerSeq)); + return; } } else @@ -1598,26 +1721,32 @@ PeerImp::onMessage(std::shared_ptr const& m) if (app_.getLedgerMaster().getValidatedLedgerAge() <= 10s && ledgerSeq > app_.getLedgerMaster().getValidLedgerIndex() + 10) { - return badData("Invalid ledger sequence " + std::to_string(ledgerSeq)); + badData("Invalid ledger sequence " + std::to_string(ledgerSeq)); + return; } } } // Verify ledger info type if (m->type() < protocol::liBASE || m->type() > protocol::liTS_CANDIDATE) - return badData("Invalid ledger info type"); + { + badData("Invalid ledger info type"); + return; + } // Verify reply error if (m->has_error() && (m->error() < protocol::reNO_LEDGER || m->error() > protocol::reBAD_REQUEST)) { - return badData("Invalid reply error"); + badData("Invalid reply error"); + return; } // Verify ledger nodes. if (m->nodes_size() <= 0 || m->nodes_size() > Tuning::hardMaxReplyNodes) { - return badData("Invalid Ledger/TXset nodes " + std::to_string(m->nodes_size())); + badData("Invalid Ledger/TXset nodes " + std::to_string(m->nodes_size())); + return; } // If there is a request cookie, attempt to relay the message @@ -1770,7 +1899,9 @@ PeerImp::onMessage(std::shared_ptr const& m) { std::lock_guard sl(recentLock_); if (!last_status_.has_newstatus() || m->has_newstatus()) + { last_status_ = *m; + } else { // preserve old status @@ -2227,7 +2358,7 @@ PeerImp::onMessage(std::shared_ptr const& m fee_.update(Resource::feeUselessData, "unsupported peer"); return; } - else if (m->version() < 2) + if (m->version() < 2) { JLOG(p_journal_.debug()) << "ValidatorListCollection: received invalid validator list " @@ -2312,8 +2443,10 @@ PeerImp::onMessage(std::shared_ptr const& m) // peer receives within IDLED seconds since the message has been // relayed. if (relayed && (stopwatch().now() - *relayed) < reduce_relay::IDLED) + { overlay_.updateSlotAndSquelch( key, val->getSignerPublic(), id_, protocol::mtVALIDATION); + } // increase duplicate validations received overlay_.reportInboundTraffic( @@ -2483,7 +2616,9 @@ PeerImp::onMessage(std::shared_ptr const& m) JLOG(p_journal_.debug()) << "GetObj: Late fetch pack for " << pLSeq; } else + { progress = true; + } } } @@ -2584,11 +2719,13 @@ PeerImp::onMessage(std::shared_ptr const& m) overlay_.addTxMetrics(m->transactions_size()); for (std::uint32_t i = 0; i < m->transactions_size(); ++i) + { handleTransaction( std::shared_ptr( m->mutable_transactions(i), [](protocol::TMTransaction*) {}), false, true); + } } void @@ -2596,7 +2733,10 @@ PeerImp::onMessage(std::shared_ptr const& m) { using on_message_fn = void (PeerImp::*)(std::shared_ptr const&); if (!strand_.running_in_this_thread()) - return post(strand_, std::bind((on_message_fn)&PeerImp::onMessage, shared_from_this(), m)); + { + post(strand_, std::bind((on_message_fn)&PeerImp::onMessage, shared_from_this(), m)); + return; + } if (!m->has_validatorpubkey()) { @@ -2621,9 +2761,13 @@ PeerImp::onMessage(std::shared_ptr const& m) std::uint32_t duration = m->has_squelchduration() ? m->squelchduration() : 0; if (!m->squelch()) + { squelch_.removeSquelch(key); + } else if (!squelch_.addSquelch(key, std::chrono::seconds{duration})) + { fee_.update(Resource::feeInvalidData, "squelch duration"); + } JLOG(p_journal_.debug()) << "onMessage: TMSquelch " << slice << " " << id() << " " << duration; } @@ -2882,9 +3026,13 @@ PeerImp::checkPropose( bool relay = false; if (isTrusted) + { relay = app_.getOPs().processTrustedProposal(peerPos); + } else + { relay = app_.config().RELAY_UNTRUSTED_PROPOSALS == 1 || cluster(); + } if (relay) { @@ -2895,11 +3043,13 @@ PeerImp::checkPropose( auto haveMessage = app_.overlay().relay(*packet, peerPos.suppressionID(), peerPos.publicKey()); if (!haveMessage.empty()) + { overlay_.updateSlotAndSquelch( peerPos.suppressionID(), peerPos.publicKey(), std::move(haveMessage), protocol::mtPROPOSE_LEDGER); + } } } @@ -3235,7 +3385,8 @@ PeerImp::processLedgerRequest(std::shared_ptr const& m) // Add requested node data to reply if (m->nodeids_size() > 0) { - auto const queryDepth{m->has_querydepth() ? m->querydepth() : (isHighLatency() ? 2 : 1)}; + std::uint32_t const defaultDepth = isHighLatency() ? 2 : 1; + auto const queryDepth{m->has_querydepth() ? m->querydepth() : defaultDepth}; std::vector> data; @@ -3347,9 +3498,13 @@ PeerImp::getScore(bool haveItem) const } if (latency) + { score -= latency->count() * spLatency; + } else + { score -= spNoLatency; + } return score; } diff --git a/src/xrpld/overlay/detail/TrafficCount.cpp b/src/xrpld/overlay/detail/TrafficCount.cpp index f782d7cf0a..2ce32b4468 100644 --- a/src/xrpld/overlay/detail/TrafficCount.cpp +++ b/src/xrpld/overlay/detail/TrafficCount.cpp @@ -36,16 +36,22 @@ TrafficCount::categorize( if (auto msg = dynamic_cast(&message)) { if (msg->type() == protocol::liTS_CANDIDATE) + { return (inbound && !msg->has_requestcookie()) ? TrafficCount::category::ld_tsc_get : TrafficCount::category::ld_tsc_share; + } if (msg->type() == protocol::liTX_NODE) + { return (inbound && !msg->has_requestcookie()) ? TrafficCount::category::ld_txn_get : TrafficCount::category::ld_txn_share; + } if (msg->type() == protocol::liAS_NODE) + { return (inbound && !msg->has_requestcookie()) ? TrafficCount::category::ld_asn_get : TrafficCount::category::ld_asn_share; + } return (inbound && !msg->has_requestcookie()) ? TrafficCount::category::ld_get : TrafficCount::category::ld_share; @@ -54,16 +60,22 @@ TrafficCount::categorize( if (auto msg = dynamic_cast(&message)) { if (msg->itype() == protocol::liTS_CANDIDATE) + { return (inbound || msg->has_requestcookie()) ? TrafficCount::category::gl_tsc_share : TrafficCount::category::gl_tsc_get; + } if (msg->itype() == protocol::liTX_NODE) + { return (inbound || msg->has_requestcookie()) ? TrafficCount::category::gl_txn_share : TrafficCount::category::gl_txn_get; + } if (msg->itype() == protocol::liAS_NODE) + { return (inbound || msg->has_requestcookie()) ? TrafficCount::category::gl_asn_share : TrafficCount::category::gl_asn_get; + } return (inbound || msg->has_requestcookie()) ? TrafficCount::category::gl_share : TrafficCount::category::gl_get; @@ -72,28 +84,40 @@ TrafficCount::categorize( if (auto msg = dynamic_cast(&message)) { if (msg->type() == protocol::TMGetObjectByHash::otLEDGER) + { return (msg->query() == inbound) ? TrafficCount::category::share_hash_ledger : TrafficCount::category::get_hash_ledger; + } if (msg->type() == protocol::TMGetObjectByHash::otTRANSACTION) + { return (msg->query() == inbound) ? TrafficCount::category::share_hash_tx : TrafficCount::category::get_hash_tx; + } if (msg->type() == protocol::TMGetObjectByHash::otTRANSACTION_NODE) + { return (msg->query() == inbound) ? TrafficCount::category::share_hash_txnode : TrafficCount::category::get_hash_txnode; + } if (msg->type() == protocol::TMGetObjectByHash::otSTATE_NODE) + { return (msg->query() == inbound) ? TrafficCount::category::share_hash_asnode : TrafficCount::category::get_hash_asnode; + } if (msg->type() == protocol::TMGetObjectByHash::otCAS_OBJECT) + { return (msg->query() == inbound) ? TrafficCount::category::share_cas_object : TrafficCount::category::get_cas_object; + } if (msg->type() == protocol::TMGetObjectByHash::otFETCH_PACK) + { return (msg->query() == inbound) ? TrafficCount::category::share_fetch_pack : TrafficCount::category::get_fetch_pack; + } if (msg->type() == protocol::TMGetObjectByHash::otTRANSACTIONS) return TrafficCount::category::get_transactions; diff --git a/src/xrpld/peerfinder/PeerfinderManager.h b/src/xrpld/peerfinder/PeerfinderManager.h index ab53068fca..b850a10975 100644 --- a/src/xrpld/peerfinder/PeerfinderManager.h +++ b/src/xrpld/peerfinder/PeerfinderManager.h @@ -74,7 +74,7 @@ struct Config /** Write the configuration into a property stream */ void - onWrite(beast::PropertyStream::Map& map); + onWrite(beast::PropertyStream::Map& map) const; /** Make PeerFinder::Config from configuration parameters * @param config server's configuration diff --git a/src/xrpld/peerfinder/detail/Bootcache.cpp b/src/xrpld/peerfinder/detail/Bootcache.cpp index af9a1ad57b..d07ec444a4 100644 --- a/src/xrpld/peerfinder/detail/Bootcache.cpp +++ b/src/xrpld/peerfinder/detail/Bootcache.cpp @@ -4,6 +4,8 @@ #include +#include + namespace xrpl { namespace PeerFinder { @@ -131,8 +133,7 @@ Bootcache::on_success(beast::IP::Endpoint const& endpoint) else { Entry entry(result.first->right); - if (entry.valence() < 0) - entry.valence() = 0; + entry.valence() = std::max(entry.valence(), 0); ++entry.valence(); m_map.erase(result.first); result = m_map.insert(value_type(endpoint, entry)); @@ -156,8 +157,7 @@ Bootcache::on_failure(beast::IP::Endpoint const& endpoint) else { Entry entry(result.first->right); - if (entry.valence() > 0) - entry.valence() = 0; + entry.valence() = std::min(entry.valence(), 0); --entry.valence(); m_map.erase(result.first); result = m_map.insert(value_type(endpoint, entry)); diff --git a/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp index 58246cd198..cc74018fc0 100644 --- a/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp +++ b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp @@ -1,6 +1,8 @@ #include #include +#include + namespace xrpl { namespace PeerFinder { @@ -51,7 +53,7 @@ Config::applyTuning() } void -Config::onWrite(beast::PropertyStream::Map& map) +Config::onWrite(beast::PropertyStream::Map& map) const { map["max_peers"] = maxPeers; map["out_peers"] = outPeers; @@ -81,8 +83,7 @@ Config::makeConfig( if (cfg.PEERS_MAX != 0) config.maxPeers = cfg.PEERS_MAX; - if (config.maxPeers < Tuning::minOutCount) - config.maxPeers = Tuning::minOutCount; + config.maxPeers = std::max(config.maxPeers, Tuning::minOutCount); config.outPeers = config.calcOutPeers(); // Calculate the number of outbound peers we want. If we dont want @@ -93,9 +94,13 @@ Config::makeConfig( // Calculate the largest number of inbound connections we could // take. if (config.maxPeers >= config.outPeers) + { config.inPeers = config.maxPeers - config.outPeers; + } else + { config.inPeers = 0; + } } else { diff --git a/src/xrpld/peerfinder/detail/PeerfinderManager.cpp b/src/xrpld/peerfinder/detail/PeerfinderManager.cpp index d04e09441c..70f082c0d5 100644 --- a/src/xrpld/peerfinder/detail/PeerfinderManager.cpp +++ b/src/xrpld/peerfinder/detail/PeerfinderManager.cpp @@ -33,8 +33,7 @@ public: beast::Journal journal, BasicConfig const& config, beast::insight::Collector::ptr const& collector) - : Manager() - , io_context_(io_context) + : io_context_(io_context) , work_(std::in_place, boost::asio::make_work_guard(io_context_)) , m_clock(clock) , m_journal(journal) diff --git a/src/xrpld/perflog/detail/PerfLogImp.cpp b/src/xrpld/perflog/detail/PerfLogImp.cpp index eb271ac91a..fc9ef70830 100644 --- a/src/xrpld/perflog/detail/PerfLogImp.cpp +++ b/src/xrpld/perflog/detail/PerfLogImp.cpp @@ -257,8 +257,10 @@ void PerfLogImp::report() { if (!logFile_) + { // If logFile_ is not writable do no further work. return; + } auto const present = system_clock::now(); if (present < lastLog_ + setup_.logInterval) @@ -345,9 +347,13 @@ PerfLogImp::rpcEnd(std::string const& method, std::uint64_t const requestId, boo } std::lock_guard lock(counter->second.mutex); if (finish) + { ++counter->second.value.finished; + } else + { ++counter->second.value.errored; + } counter->second.value.duration += std::chrono::duration_cast(steady_clock::now() - startTime); } @@ -437,7 +443,7 @@ PerfLogImp::rotate() void PerfLogImp::start() { - if (setup_.perfLog.size()) + if (!setup_.perfLog.empty()) thread_ = std::thread(&PerfLogImp::run, this); } @@ -463,7 +469,7 @@ setup_PerfLog(Section const& section, boost::filesystem::path const& configDir) PerfLog::Setup setup; std::string perfLog; set(perfLog, "perf_log", section); - if (perfLog.size()) + if (!perfLog.empty()) { setup.perfLog = boost::filesystem::path(perfLog); if (setup.perfLog.is_relative()) diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index ec970b107e..04cf0420b7 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -42,9 +42,13 @@ handle(JsonContext& context, Object& object) auto status = handler.check(); if (status) + { status.inject(object); + } else + { handler.writeResult(object); + } return status; } @@ -172,9 +176,11 @@ private: { if (overlappingApiVersion( table_.equal_range(entry.name_), entry.minApiVer_, entry.maxApiVer_)) + { LogicError( std::string("Handler for ") + entry.name_ + " overlaps with an existing handler"); + } table_.insert({entry.name_, entry}); } @@ -232,9 +238,11 @@ private: table_.equal_range(HandlerImpl::name), HandlerImpl::minApiVer, HandlerImpl::maxApiVer)) + { LogicError( std::string("Handler for ") + HandlerImpl::name + " overlaps with an existing handler"); + } table_.insert({HandlerImpl::name, handlerFrom()}); } diff --git a/src/xrpld/rpc/detail/RPCCall.cpp b/src/xrpld/rpc/detail/RPCCall.cpp index 43ca166f9f..cd36208294 100644 --- a/src/xrpld/rpc/detail/RPCCall.cpp +++ b/src/xrpld/rpc/detail/RPCCall.cpp @@ -116,7 +116,7 @@ private: jvResult[jss::currency] = strCurrency; - if (strIssuer.length()) + if (!strIssuer.empty()) { // Could confirm issuer is a valid Ripple address. jvResult[jss::issuer] = strIssuer; @@ -124,11 +124,9 @@ private: return jvResult; } - else - { - return RPC::make_param_error( - std::string("Invalid currency/issuer '") + strCurrencyIssuer + "'"); - } + + return RPC::make_param_error( + std::string("Invalid currency/issuer '") + strCurrencyIssuer + "'"); } static bool @@ -212,6 +210,7 @@ private: // account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] // [count] [descending] Json::Value + // NOLINTNEXTLINE(readability-make-member-function-const) parseAccountTransactions(Json::Value const& jvParams) { Json::Value jvRequest(Json::objectValue); @@ -298,19 +297,15 @@ private: { return jvTakerPays; } - else - { - jvRequest[jss::taker_pays] = jvTakerPays; - } + + jvRequest[jss::taker_pays] = jvTakerPays; if (isRpcError(jvTakerGets)) { return jvTakerGets; } - else - { - jvRequest[jss::taker_gets] = jvTakerGets; - } + + jvRequest[jss::taker_gets] = jvTakerGets; if (jvParams.size() >= 3) { @@ -366,9 +361,13 @@ private: std::string input = jvParams[0u].asString(); if (input.find_first_not_of("0123456789") == std::string::npos) + { jvRequest["can_delete"] = jvParams[0u].asUInt(); + } else + { jvRequest["can_delete"] = input; + } return jvRequest; } @@ -447,11 +446,17 @@ private: // determines whether an amendment is vetoed - so "reject" means // that jss::vetoed is true. if (boost::iequals(action, "reject")) + { jvRequest[jss::vetoed] = Json::Value(true); + } else if (boost::iequals(action, "accept")) + { jvRequest[jss::vetoed] = Json::Value(false); + } else + { return rpcError(rpcINVALID_PARAMS); + } } return jvRequest; @@ -967,8 +972,7 @@ private: return jvRequest; } - else if ( - (jvParams.size() >= 2 || bOffline) && reader.parse(jvParams[1u].asString(), txJSON)) + if ((jvParams.size() >= 2 || bOffline) && reader.parse(jvParams[1u].asString(), txJSON)) { // Signing or submitting tx_json. Json::Value jvRequest{Json::objectValue}; @@ -1055,9 +1059,13 @@ private: } if (jvParams[0u].asString().length() == 16) + { jvRequest[jss::ctid] = jvParams[0u].asString(); + } else + { jvRequest[jss::transaction] = jvParams[0u].asString(); + } return jvRequest; } @@ -1123,9 +1131,13 @@ private: if (param[0] != 'r') { if (param.size() == 64) + { jvRequest[jss::ledger_hash] = param; + } else + { jvRequest[jss::ledger_index] = param; + } if (size <= index) return RPC::make_param_error("Invalid hotwallet"); @@ -1355,10 +1367,12 @@ struct RPCCallImp // Receive reply if (strData.empty()) + { Throw( "no response from server. Please " "ensure that the rippled server is running in another " "process."); + } // Parse reply JLOG(j.debug()) << "RPC reply: " << strData << std::endl; @@ -1435,9 +1449,13 @@ rpcCmdToJson( }; if (jvRequest.isObject()) + { insert_api_version(jvRequest); + } else if (jvRequest.isArray()) + { std::for_each(jvRequest.begin(), jvRequest.end(), insert_api_version); + } JLOG(j.trace()) << "RPC Request: " << jvRequest << std::endl; return jvRequest; @@ -1500,7 +1518,9 @@ rpcClient( jvRequest["admin_password"] = setup.client.admin_password; if (jvRequest.isObject()) + { jvParams.append(jvRequest); + } else if (jvRequest.isArray()) { for (Json::UInt i = 0; i < jvRequest.size(); ++i) @@ -1516,9 +1536,12 @@ rpcClient( setup.client.user, setup.client.password, "", - jvRequest.isMember(jss::method) // Allow parser to rewrite method. - ? jvRequest[jss::method].asString() - : jvRequest.isArray() ? "batch" : args[0], + // Allow parser to rewrite method. + [&]() -> std::string { + if (jvRequest.isMember(jss::method)) + return jvRequest[jss::method].asString(); + return jvRequest.isArray() ? "batch" : args[0]; + }(), jvParams, // Parsed, execute. setup.client.secure != 0, // Use SSL config.quiet(), @@ -1557,11 +1580,17 @@ rpcClient( { jvOutput[jss::status] = "error"; if (jvOutput.isMember(jss::error_code)) + { nRet = std::stoi(jvOutput[jss::error_code].asString()); + } else if (jvOutput[jss::error].isMember(jss::error_code)) + { nRet = std::stoi(jvOutput[jss::error][jss::error_code].asString()); + } else + { nRet = rpcBAD_SYNTAX; + } } // YYY We could have a command line flag for single line output for diff --git a/src/xrpld/rpc/detail/RPCHandler.cpp b/src/xrpld/rpc/detail/RPCHandler.cpp index 2066c8a5e9..840ebd5946 100644 --- a/src/xrpld/rpc/detail/RPCHandler.cpp +++ b/src/xrpld/rpc/detail/RPCHandler.cpp @@ -215,11 +215,9 @@ doCommand(RPC::JsonContext& context, Json::Value& result) return ret; } - else - { - auto ret = callMethod(context, method, handler->name_, result); - return ret; - } + + auto ret = callMethod(context, method, handler->name_, result); + return ret; } return rpcUNKNOWN_COMMAND; diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 385bc7f4af..832ff778e1 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -24,9 +24,13 @@ getStartHint(std::shared_ptr const& sle, AccountID const& accountID) if (sle->getType() == ltRIPPLE_STATE) { if (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID) + { return sle->getFieldU64(sfLowNode); - else if (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID) + } + if (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID) + { return sle->getFieldU64(sfHighNode); + } } if (!sle->isFieldPresent(sfOwnerNode)) @@ -46,7 +50,7 @@ isRelatedToAccount( return (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID) || (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID); } - else if (sle->isFieldPresent(sfAccount)) + if (sle->isFieldPresent(sfAccount)) { // If there's an sfAccount present, also test the sfDestination, if // present. This will match objects such as Escrows (ltESCROW), Payment @@ -57,12 +61,12 @@ isRelatedToAccount( return sle->getAccountID(sfAccount) == accountID || (sle->isFieldPresent(sfDestination) && sle->getAccountID(sfDestination) == accountID); } - else if (sle->getType() == ltSIGNER_LIST) + if (sle->getType() == ltSIGNER_LIST) { Keylet const accountSignerList = keylet::signers(accountID); return sle->key() == accountSignerList.key; } - else if (sle->getType() == ltNFTOKEN_OFFER) + if (sle->getType() == ltNFTOKEN_OFFER) { // Do not check the sfDestination field. NFToken Offers are NOT added to // the Destination account's directory. @@ -234,9 +238,13 @@ keypairForSignature(Json::Value const& params, Json::Value& error, unsigned int if (!keyType) { if (apiVersion > 1u) + { error = RPC::make_error(rpcBAD_KEY_TYPE); + } else + { error = RPC::invalid_field_error(jss::key_type); + } return {}; } @@ -279,7 +287,9 @@ keypairForSignature(Json::Value const& params, Json::Value& error, unsigned int if (!seed) { if (has_key_type) + { seed = getSeedFromRPC(params, error); + } else { if (!params[jss::secret].isString()) diff --git a/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp b/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp index acf9ecd23a..54ff515894 100644 --- a/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp @@ -78,10 +78,12 @@ ledgerFromRequest(T& ledger, JsonContext const& context) // while `ledger` is still supported, it is deprecated // and therefore shouldn't be mentioned in the error message if (hasLedger) + { return { rpcINVALID_PARAMS, "Exactly one of 'ledger', 'ledger_hash', or " "'ledger_index' can be specified."}; + } return { rpcINVALID_PARAMS, "Exactly one of 'ledger_hash' or " @@ -97,9 +99,11 @@ ledgerFromRequest(T& ledger, JsonContext const& context) return {rpcINVALID_PARAMS, expected_field_message(jss::ledger, "string or number")}; } if (legacyLedger.isString() && legacyLedger.asString().size() == 64) + { return ledgerFromHash(ledger, legacyLedger, context, jss::ledger); - else - return ledgerFromIndex(ledger, legacyLedger, context, jss::ledger); + } + + return ledgerFromIndex(ledger, legacyLedger, context, jss::ledger); } if (hasHash) @@ -182,17 +186,15 @@ ledgerFromSpecifier( { return getLedger(ledger, LedgerShortcut::Validated, context); } - else + + if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT || + shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED) { - if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT || - shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED) - { - return getLedger(ledger, LedgerShortcut::Current, context); - } - else if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED) - { - return getLedger(ledger, LedgerShortcut::Closed, context); - } + return getLedger(ledger, LedgerShortcut::Current, context); + } + if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED) + { + return getLedger(ledger, LedgerShortcut::Closed, context); } } } diff --git a/src/xrpld/rpc/detail/RPCSub.cpp b/src/xrpld/rpc/detail/RPCSub.cpp index 49a78d0755..233981001a 100644 --- a/src/xrpld/rpc/detail/RPCSub.cpp +++ b/src/xrpld/rpc/detail/RPCSub.cpp @@ -34,16 +34,29 @@ public: parsedURL pUrl; if (!parseUrl(pUrl, strUrl)) + { Throw("Failed to parse url."); + } else if (pUrl.scheme == "https") + { mSSL = true; + } else if (pUrl.scheme != "http") + { Throw("Only http and https is supported."); + } mSeq = 1; mIp = pUrl.domain; - mPort = (!pUrl.port) ? (mSSL ? 443 : 80) : *pUrl.port; + if (!pUrl.port) + { + mPort = mSSL ? 443 : 80; + } + else + { + mPort = *pUrl.port; + } mPath = pUrl.path; JLOG(j_.info()) << "RPCCall::fromNetwork sub: ip=" << mIp << " port=" << mPort diff --git a/src/xrpld/rpc/detail/Role.cpp b/src/xrpld/rpc/detail/Role.cpp index e040a55c69..499787cece 100644 --- a/src/xrpld/rpc/detail/Role.cpp +++ b/src/xrpld/rpc/detail/Role.cpp @@ -83,7 +83,7 @@ requestRole( if (ipAllowed(remoteIp.address(), port.secure_gateway_nets_v4, port.secure_gateway_nets_v6)) { - if (user.size()) + if (!user.empty()) return Role::IDENTIFIED; return Role::PROXY; } @@ -137,9 +137,11 @@ extractIpAddrFromField(std::string_view field) { std::size_t const firstNonSpace = ret.find_first_not_of(' '); if (firstNonSpace == std::string_view::npos) + { // We know there's at least one leading space. So if we got // npos, then it must be all spaces. Return empty string_view. return {}; + } ret = ret.substr(firstNonSpace); } @@ -151,9 +153,11 @@ extractIpAddrFromField(std::string_view field) { std::size_t const lastNonSpace = ret.find_last_not_of(" \r\n"); if (lastNonSpace == std::string_view::npos) + { // We know there's at least one leading space. So if we // got npos, then it must be all spaces. return {}; + } ret = ret.substr(0, lastNonSpace + 1); } diff --git a/src/xrpld/rpc/detail/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp index 39f0be6722..f5187d6285 100644 --- a/src/xrpld/rpc/detail/ServerHandler.cpp +++ b/src/xrpld/rpc/detail/ServerHandler.cpp @@ -363,9 +363,13 @@ void logDuration(Json::Value const& request, T const& duration, beast::Journal& journal) { using namespace std::chrono_literals; - auto const level = (duration >= 10s) ? journal.error() - : (duration >= 1s) ? journal.warn() - : journal.debug(); + auto const level = [&]() { + if (duration >= 10s) + return journal.error(); + if (duration >= 1s) + return journal.warn(); + return journal.debug(); + }(); JLOG(level) << "RPC request processing duration = " << std::chrono::duration_cast(duration).count() @@ -535,9 +539,13 @@ ServerHandler::processSession( }()); if (beast::rfc2616::is_keep_alive(session->request())) + { session->complete(); + } else + { session->close(true); + } } static Json::Value @@ -643,8 +651,10 @@ ServerHandler::processRequest( auto role = Role::FORBID; auto required = Role::FORBID; if (jsonRPC.isMember(jss::method) && jsonRPC[jss::method].isString()) + { required = RPC::roleRequired( apiVersion, app_.config().BETA_RPC_API, jsonRPC[jss::method].asString()); + } if (jsonRPC.isMember(jss::params) && jsonRPC[jss::params].isArray() && jsonRPC[jss::params].size() > 0 && jsonRPC[jss::params][Json::UInt(0)].isObjectOrNull()) @@ -749,8 +759,9 @@ ServerHandler::processRequest( { params = jsonRPC[jss::params]; if (!params) + { params = Json::Value(Json::objectValue); - + } else if (!params.isArray() || params.size() != 1) { usage.charge(Resource::feeMalformedRPC); @@ -909,9 +920,13 @@ ServerHandler::processRequest( if (params.isMember(jss::id)) r[jss::id] = params[jss::id]; if (batch) + { reply.append(std::move(r)); + } else + { reply = std::move(r); + } if (reply.isMember(jss::result) && reply[jss::result].isMember(jss::result)) { @@ -957,9 +972,13 @@ ServerHandler::processRequest( { static int const maxSize = 10000; if (response.size() <= maxSize) + { stream << "Reply: " << response; + } else + { stream << "Reply: " << response.substr(0, maxSize); + } } HTTPReply(httpStatus, response, output, rpcJ); @@ -1009,10 +1028,14 @@ ServerHandler::Setup::makeContexts() if (p.secure()) { if (p.ssl_key.empty() && p.ssl_cert.empty() && p.ssl_chain.empty()) + { p.context = make_SSLContext(p.ssl_ciphers); + } else + { p.context = make_SSLContextAuthed(p.ssl_key, p.ssl_cert, p.ssl_chain, p.ssl_ciphers); + } } else { @@ -1113,9 +1136,13 @@ parse_Ports(Config const& config, std::ostream& log) // Remove the peer protocol, and if that would // leave the port empty, remove the port as well if (p.erase("peer") && p.empty()) + { it = result.erase(it); + } else + { ++it; + } } } else @@ -1143,15 +1170,22 @@ setup_Client(ServerHandler::Setup& setup) { decltype(setup.ports)::const_iterator iter; for (iter = setup.ports.cbegin(); iter != setup.ports.cend(); ++iter) + { if (iter->protocol.count("http") > 0 || iter->protocol.count("https") > 0) break; + } if (iter == setup.ports.cend()) return; setup.client.secure = iter->protocol.count("https") > 0; - setup.client.ip = beast::IP::is_unspecified(iter->ip) ? - // VFALCO HACK! to make localhost work - (iter->ip.is_v6() ? "::1" : "127.0.0.1") - : iter->ip.to_string(); + if (beast::IP::is_unspecified(iter->ip)) + { + // VFALCO HACK! to make localhost work + setup.client.ip = iter->ip.is_v6() ? "::1" : "127.0.0.1"; + } + else + { + setup.client.ip = iter->ip.to_string(); + } setup.client.port = iter->port; setup.client.user = iter->user; setup.client.password = iter->password; diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 8afe3612fe..80c608dbbf 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -72,7 +72,7 @@ public: bool validMultiSign() const { - return isMultiSigning() && multiSignPublicKey_ && multiSignature_.size(); + return isMultiSigning() && multiSignPublicKey_ && !multiSignature_.empty(); } // Don't call this method unless isMultiSigning() returns true. @@ -179,11 +179,15 @@ checkPayment( if (tx_json.isMember(jss::Amount)) { if (tx_json[jss::DeliverMax] != tx_json[jss::Amount]) + { return RPC::make_error( rpcINVALID_PARAMS, "Cannot specify differing 'Amount' and 'DeliverMax'"); + } } else + { tx_json[jss::Amount] = tx_json[jss::DeliverMax]; + } tx_json.removeMember(jss::DeliverMax); } @@ -204,12 +208,16 @@ checkPayment( return RPC::invalid_field_error("tx_json.Destination"); if (params.isMember(jss::build_path) && ((doPath == false) || amount.holds())) + { return RPC::make_error( rpcINVALID_PARAMS, "Field 'build_path' not allowed in this context."); + } if (tx_json.isMember(jss::Paths) && params.isMember(jss::build_path)) + { return RPC::make_error( rpcINVALID_PARAMS, "Cannot specify both 'tx_json.Paths' and 'build_path'"); + } std::optional domain; if (tx_json.isMember(sfDomainID.jsonName)) @@ -220,10 +228,8 @@ checkPayment( { return RPC::make_error(rpcDOMAIN_MALFORMED, "Unable to parse 'DomainID'."); } - else - { - domain = num; - } + + domain = num; } if (!tx_json.isMember(jss::Paths) && params.isMember(jss::build_path)) @@ -338,9 +344,13 @@ checkTxJsonFields( if (verify && !config.standalone() && (validatedLedgerAge > Tuning::maxValidatedLedgerAge)) { if (apiVersion == 1) + { ret.first = rpcError(rpcNO_CURRENT); + } else + { ret.first = rpcError(rpcNOT_SYNCED); + } return ret; } @@ -525,8 +535,10 @@ transactionPreProcessImpl( if (verify) { if (!sle) + { // XXX Ignore transactions for accounts not created. return rpcError(rpcSRC_ACT_NOT_FOUND); + } JLOG(j.trace()) << "verify: " << toBase58(calcAccountID(pk)) << " : " << toBase58(srcAddressID); @@ -592,8 +604,10 @@ transactionPreProcessImpl( { // If the target object doesn't exist, make one. if (!parsed.object->isFieldPresent(*signatureTarget)) + { parsed.object->setFieldObject( *signatureTarget, STObject{*signatureTemplate, *signatureTarget}); + } sigObject = &parsed.object->peekFieldObject(*signatureTarget); } sigObject->setFieldVL( @@ -666,8 +680,10 @@ transactionConstructImpl( // Check the signature if that's called for. auto sttxNew = std::make_shared(sit); if (!app.checkSigs()) + { forceValidity( app.getHashRouter(), sttxNew->getTransactionID(), Validity::SigGoodOnly); + } if (checkValidity(app.getHashRouter(), *sttxNew, rules).first != Validity::Valid) { ret.first = RPC::make_error(rpcINTERNAL, "Invalid signature."); @@ -714,7 +730,9 @@ transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion) jvResult[jss::hash] = to_string(tpTrans->getID()); } else + { jvResult[jss::tx_json] = tpTrans->getJson(JsonOptions::none); + } RPC::insertDeliverMax( jvResult[jss::tx_json], tpTrans->getSTransaction()->getTxnType(), apiVersion); @@ -880,9 +898,11 @@ checkFee( { mult = request[jss::fee_mult_max].asInt(); if (mult < 0) + { return RPC::make_error( rpcINVALID_PARAMS, RPC::expected_field_message(jss::fee_mult_max, "a positive integer")); + } } else { @@ -896,9 +916,11 @@ checkFee( { div = request[jss::fee_div_max].asInt(); if (div <= 0) + { return RPC::make_error( rpcINVALID_PARAMS, RPC::expected_field_message(jss::fee_div_max, "a positive integer")); + } } else { @@ -1024,8 +1046,10 @@ checkMultiSignFields(Json::Value const& jvRequest) // Account. if (!jvRequest.isMember(jss::signature_target) && !tx_json[sfSigningPubKey.getJsonName()].asString().empty()) + { return RPC::make_error( rpcINVALID_PARAMS, "When multi-signing 'tx_json.SigningPubKey' must be empty."); + } return Json::Value(); } diff --git a/src/xrpld/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp index e174a49f87..42e44f004d 100644 --- a/src/xrpld/rpc/handlers/AMMInfo.cpp +++ b/src/xrpld/rpc/handlers/AMMInfo.cpp @@ -75,17 +75,25 @@ doAMMInfo(RPC::JsonContext& context) if (params.isMember(jss::asset)) { if (auto const i = getIssue(params[jss::asset], context.j)) + { issue1 = *i; + } else + { return Unexpected(i.error()); + } } if (params.isMember(jss::asset2)) { if (auto const i = getIssue(params[jss::asset2], context.j)) + { issue2 = *i; + } else + { return Unexpected(i.error()); + } } if (params.isMember(jss::amm_account)) @@ -204,11 +212,15 @@ doAMMInfo(RPC::JsonContext& context) } if (!isXRP(asset1Balance)) + { ammResult[jss::asset_frozen] = isFrozen(*ledger, ammAccountID, issue1.currency, issue1.account); + } if (!isXRP(asset2Balance)) + { ammResult[jss::asset2_frozen] = isFrozen(*ledger, ammAccountID, issue2.currency, issue2.account); + } result[jss::amm] = std::move(ammResult); if (!result.isMember(jss::ledger_index) && !result.isMember(jss::ledger_hash)) diff --git a/src/xrpld/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp index e88da097f7..f144c934ec 100644 --- a/src/xrpld/rpc/handlers/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/AccountInfo.cpp @@ -84,7 +84,9 @@ doAccountInfo(RPC::JsonContext& context) strIdent = params[jss::ident].asString(); } else + { return RPC::missing_field_error(jss::account); + } std::shared_ptr ledger; auto result = RPC::lookupLedger(ledger, context); @@ -150,12 +152,16 @@ doAccountInfo(RPC::JsonContext& context) acctFlags[lsf.first.data()] = sleAccepted->isFlag(lsf.second); if (ledger->rules().enabled(featureClawback)) + { acctFlags[allowTrustLineClawbackFlag.first.data()] = sleAccepted->isFlag(allowTrustLineClawbackFlag.second); + } if (ledger->rules().enabled(featureTokenEscrow)) + { acctFlags[allowTrustLineLockingFlag.first.data()] = sleAccepted->isFlag(allowTrustLineLockingFlag.second); + } result[jss::account_flags] = std::move(acctFlags); @@ -300,7 +306,9 @@ doAccountInfo(RPC::JsonContext& context) jvQueueData[jss::max_spend_drops_total] = to_string(totalSpend); } else + { jvQueueData[jss::txn_count] = 0u; + } result[jss::queue_data] = std::move(jvQueueData); } diff --git a/src/xrpld/rpc/handlers/AccountLines.cpp b/src/xrpld/rpc/handlers/AccountLines.cpp index d065180c64..952141fb8d 100644 --- a/src/xrpld/rpc/handlers/AccountLines.cpp +++ b/src/xrpld/rpc/handlers/AccountLines.cpp @@ -191,9 +191,13 @@ doAccountLines(RPC::JsonContext& context) if (visitData.ignoreDefault) { if (sleCur->getFieldAmount(sfLowLimit).getIssuer() == visitData.accountID) + { ignore = !(sleCur->getFieldU32(sfFlags) & lsfLowReserve); + } else + { ignore = !(sleCur->getFieldU32(sfFlags) & lsfHighReserve); + } } if (!ignore && count <= limit) diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index f5f48d8050..cd67391da8 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -144,9 +144,13 @@ doAccountNFTs(RPC::JsonContext& context) } if (auto npm = (*cp)[~sfNextPageMin]) + { cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm)); + } else + { cp = nullptr; + } } if (markerSet && !markerFound) @@ -229,9 +233,13 @@ getAccountObjects( jvObjects.append(cp->getJson(JsonOptions::none)); auto const npm = (*cp)[~sfNextPageMin]; if (npm) + { cp = ledger.read(Keylet(ltNFTOKEN_PAGE, *npm)); + } else + { cp = nullptr; + } if (--mlimit == 0) { @@ -429,7 +437,7 @@ doAccountObjects(RPC::JsonContext& context) rpcStatus.inject(result); return result; } - else if (type != ltANY) + if (type != ltANY) { typeFilter = std::vector({type}); } diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index 6c227b16b9..d7bffe5d95 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -59,7 +59,7 @@ parseLedgerArgs(RPC::Context& context, Json::Value const& params) return LedgerRange{min, max}; } - else if (params.isMember(jss::ledger_hash)) + if (params.isMember(jss::ledger_hash)) { auto& hashValue = params[jss::ledger_hash]; if (!hashValue.isString()) @@ -78,21 +78,29 @@ parseLedgerArgs(RPC::Context& context, Json::Value const& params) } return hash; } - else if (params.isMember(jss::ledger_index)) + if (params.isMember(jss::ledger_index)) { LedgerSpecifier ledger; if (params[jss::ledger_index].isNumeric()) + { ledger = params[jss::ledger_index].asUInt(); + } else { std::string ledgerStr = params[jss::ledger_index].asString(); if (ledgerStr == "current" || ledgerStr.empty()) + { ledger = LedgerShortcut::Current; + } else if (ledgerStr == "closed") + { ledger = LedgerShortcut::Closed; + } else if (ledgerStr == "validated") + { ledger = LedgerShortcut::Validated; + } else { RPC::Status status{rpcINVALID_PARAMS, "ledger_index string malformed"}; @@ -298,7 +306,9 @@ populateJsonResponse( jvObj[jss::close_time_iso] = to_string_iso(*closeTime); } else + { jvObj[json_tx] = txn->getJson(JsonOptions::include_date); + } auto const& sttx = txn->getSTransaction(); RPC::insertDeliverMax(jvObj[json_tx], sttx->getTxnType(), context.apiVersion); @@ -404,10 +414,8 @@ doAccountTxJson(RPC::JsonContext& context) { return *jv; } - else - { - args.ledger = std::get>(parseRes); - } + + args.ledger = std::get>(parseRes); if (params.isMember(jss::marker)) { diff --git a/src/xrpld/rpc/handlers/BlackList.cpp b/src/xrpld/rpc/handlers/BlackList.cpp index 102041b8d0..86abe53686 100644 --- a/src/xrpld/rpc/handlers/BlackList.cpp +++ b/src/xrpld/rpc/handlers/BlackList.cpp @@ -11,9 +11,11 @@ doBlackList(RPC::JsonContext& context) { auto& rm = context.app.getResourceManager(); if (context.params.isMember(jss::threshold)) + { return rm.getJson(context.params[jss::threshold].asInt()); - else - return rm.getJson(); + } + + return rm.getJson(); } } // namespace xrpl diff --git a/src/xrpld/rpc/handlers/BookOffers.cpp b/src/xrpld/rpc/handlers/BookOffers.cpp index 593f3e1fa2..ec53473821 100644 --- a/src/xrpld/rpc/handlers/BookOffers.cpp +++ b/src/xrpld/rpc/handlers/BookOffers.cpp @@ -83,12 +83,16 @@ doBookOffers(RPC::JsonContext& context) return RPC::expected_field_error("taker_pays.issuer", "string"); if (!to_issuer(pay_issuer, taker_pays[jss::issuer].asString())) + { return RPC::make_error( rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', bad issuer."); + } if (pay_issuer == noAccount()) + { return RPC::make_error( rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', bad issuer account one."); + } } else { @@ -96,14 +100,18 @@ doBookOffers(RPC::JsonContext& context) } if (isXRP(pay_currency) && !isXRP(pay_issuer)) + { return RPC::make_error( rpcSRC_ISR_MALFORMED, "Unneeded field 'taker_pays.issuer' for " "XRP currency specification."); + } if (!isXRP(pay_currency) && isXRP(pay_issuer)) + { return RPC::make_error( rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', expected non-XRP issuer."); + } AccountID get_issuer; @@ -113,12 +121,16 @@ doBookOffers(RPC::JsonContext& context) return RPC::expected_field_error("taker_gets.issuer", "string"); if (!to_issuer(get_issuer, taker_gets[jss::issuer].asString())) + { return RPC::make_error( rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer."); + } if (get_issuer == noAccount()) + { return RPC::make_error( rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer account one."); + } } else { @@ -126,14 +138,18 @@ doBookOffers(RPC::JsonContext& context) } if (isXRP(get_currency) && !isXRP(get_issuer)) + { return RPC::make_error( rpcDST_ISR_MALFORMED, "Unneeded field 'taker_gets.issuer' for " "XRP currency specification."); + } if (!isXRP(get_currency) && isXRP(get_issuer)) + { return RPC::make_error( rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', expected non-XRP issuer."); + } std::optional takerID; if (context.params.isMember(jss::taker)) @@ -155,10 +171,8 @@ doBookOffers(RPC::JsonContext& context) { return RPC::make_error(rpcDOMAIN_MALFORMED, "Unable to parse domain."); } - else - { - domain = num; - } + + domain = num; } if (pay_currency == get_currency && pay_issuer == get_issuer) diff --git a/src/xrpld/rpc/handlers/Connect.cpp b/src/xrpld/rpc/handlers/Connect.cpp index 415adbd2fd..292cd50cbb 100644 --- a/src/xrpld/rpc/handlers/Connect.cpp +++ b/src/xrpld/rpc/handlers/Connect.cpp @@ -36,9 +36,13 @@ doConnect(RPC::JsonContext& context) int iPort = 0; if (context.params.isMember(jss::port)) + { iPort = context.params[jss::port].asInt(); + } else + { iPort = DEFAULT_PEER_PORT; + } auto const ip_str = context.params[jss::ip].asString(); auto ip = beast::IP::Endpoint::from_string(ip_str); diff --git a/src/xrpld/rpc/handlers/DepositAuthorized.cpp b/src/xrpld/rpc/handlers/DepositAuthorized.cpp index 7bad908c51..7ab7e30c8a 100644 --- a/src/xrpld/rpc/handlers/DepositAuthorized.cpp +++ b/src/xrpld/rpc/handlers/DepositAuthorized.cpp @@ -27,8 +27,10 @@ doDepositAuthorized(RPC::JsonContext& context) if (!params.isMember(jss::source_account)) return RPC::missing_field_error(jss::source_account); if (!params[jss::source_account].isString()) + { return RPC::make_error( rpcINVALID_PARAMS, RPC::expected_field_message(jss::source_account, "a string")); + } auto srcID = parseBase58(params[jss::source_account].asString()); if (!srcID) @@ -39,8 +41,10 @@ doDepositAuthorized(RPC::JsonContext& context) if (!params.isMember(jss::destination_account)) return RPC::missing_field_error(jss::destination_account); if (!params[jss::destination_account].isString()) + { return RPC::make_error( rpcINVALID_PARAMS, RPC::expected_field_message(jss::destination_account, "a string")); + } auto dstID = parseBase58(params[jss::destination_account].asString()); if (!dstID) @@ -84,7 +88,7 @@ doDepositAuthorized(RPC::JsonContext& context) RPC::expected_field_message( jss::credentials, "is non-empty array of CredentialID(hash256)")); } - else if (creds.size() > maxCredentialsArraySize) + if (creds.size() > maxCredentialsArraySize) { return RPC::make_error( rpcINVALID_PARAMS, RPC::expected_field_message(jss::credentials, "array too long")); @@ -151,8 +155,10 @@ doDepositAuthorized(RPC::JsonContext& context) // not set, then the deposit should be fine. bool depositAuthorized = true; if (reqAuth) + { depositAuthorized = ledger->exists(keylet::depositPreauth(dstAcct, srcAcct)) || (credentialsPresent && ledger->exists(keylet::depositPreauth(dstAcct, sorted))); + } result[jss::source_account] = params[jss::source_account].asString(); result[jss::destination_account] = params[jss::destination_account].asString(); diff --git a/src/xrpld/rpc/handlers/Feature1.cpp b/src/xrpld/rpc/handlers/Feature1.cpp index bd1e501506..24ff0d62b8 100644 --- a/src/xrpld/rpc/handlers/Feature1.cpp +++ b/src/xrpld/rpc/handlers/Feature1.cpp @@ -61,9 +61,13 @@ doFeature(RPC::JsonContext& context) return rpcError(rpcNO_PERMISSION); if (context.params[jss::vetoed].asBool()) + { table.veto(feature); + } else + { table.unVeto(feature); + } } Json::Value jvReply = table.getJson(feature, isAdmin); diff --git a/src/xrpld/rpc/handlers/GatewayBalances.cpp b/src/xrpld/rpc/handlers/GatewayBalances.cpp index a2176ab388..60e031c812 100644 --- a/src/xrpld/rpc/handlers/GatewayBalances.cpp +++ b/src/xrpld/rpc/handlers/GatewayBalances.cpp @@ -173,7 +173,7 @@ doGatewayBalances(RPC::JsonContext& context) // A positive balance means the cold wallet has an asset // (unusual) - if (hotWallets.count(peer) > 0) + if (hotWallets.contains(peer)) { // This is a specified hot wallet hotBalances[peer].push_back(-rs->getBalance()); diff --git a/src/xrpld/rpc/handlers/LedgerData.cpp b/src/xrpld/rpc/handlers/LedgerData.cpp index 308f4b4436..733d1c99c6 100644 --- a/src/xrpld/rpc/handlers/LedgerData.cpp +++ b/src/xrpld/rpc/handlers/LedgerData.cpp @@ -140,14 +140,14 @@ doLedgerDataGrpc(RPC::GRPCContext& con { startKey = *key; } - else if (request.marker().size() != 0) + else if (!request.marker().empty()) { grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT, "marker malformed"}; return {response, errorStatus}; } auto e = ledger->sles.end(); - if (request.end_marker().size() != 0) + if (!request.end_marker().empty()) { auto const key = uint256::fromVoidChecked(request.end_marker()); diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index e4e8f52fd7..8e3b7f214d 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -70,9 +70,11 @@ parseIndex(Json::Value const& params, Json::StaticString const fieldName, unsign if (index == jss::nunl) return keylet::negativeUNL().key; if (index == jss::hashes) + { // Note this only finds the "short" skip list. Use "hashes":index to // get the long list. return keylet::skip().key; + } } return parseObjectID(params, fieldName, "hex string"); } @@ -532,8 +534,10 @@ parseMPTokenIssuance( { auto const mptIssuanceID = LedgerEntryHelpers::parse(params); if (!mptIssuanceID) + { return LedgerEntryHelpers::invalidFieldError( "malformedMPTokenIssuance", fieldName, "Hash192"); + } return keylet::mptIssuance(*mptIssuanceID).key; } @@ -901,8 +905,8 @@ doLedgerEntry(RPC::JsonContext& context) // this exception return an invalidParam error. return RPC::make_error(rpcINVALID_PARAMS); } - else - throw; + + throw; } // Return the computed index regardless of whether the node exists. diff --git a/src/xrpld/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp index 6d188f8520..43c9780bb0 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerHandler.cpp @@ -215,11 +215,17 @@ doLedgerGrpc(RPC::GRPCContext& context) obj->set_data(inDesired->data(), inDesired->size()); } if (inBase && inDesired) + { obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::MODIFIED); + } else if (inBase && !inDesired) + { obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::DELETED); + } else + { obj->set_mod_type(org::xrpl::rpc::v1::RawLedgerObject::CREATED); + } auto const blob = inDesired ? inDesired->slice() : inBase->slice(); auto const objectType = static_cast(blob[1] << 8 | blob[2]); diff --git a/src/xrpld/rpc/handlers/LogLevel.cpp b/src/xrpld/rpc/handlers/LogLevel.cpp index 2596cd6c70..2bc1beb7d4 100644 --- a/src/xrpld/rpc/handlers/LogLevel.cpp +++ b/src/xrpld/rpc/handlers/LogLevel.cpp @@ -52,9 +52,13 @@ doLogLevel(RPC::JsonContext& context) std::string partition(context.params[jss::partition].asString()); if (boost::iequals(partition, "base")) + { context.app.logs().threshold(severity); + } else + { context.app.logs().get(partition).threshold(severity); + } return Json::objectValue; } diff --git a/src/xrpld/rpc/handlers/NoRippleCheck.cpp b/src/xrpld/rpc/handlers/NoRippleCheck.cpp index 9985591303..f21a67a31d 100644 --- a/src/xrpld/rpc/handlers/NoRippleCheck.cpp +++ b/src/xrpld/rpc/handlers/NoRippleCheck.cpp @@ -55,9 +55,13 @@ doNoRippleCheck(RPC::JsonContext& context) { std::string const role = params["role"].asString(); if (role == "gateway") + { roleGateway = true; + } else if (role != "user") + { return RPC::invalid_field_error("role"); + } } unsigned int limit = 0; diff --git a/src/xrpld/rpc/handlers/PayChanClaim.cpp b/src/xrpld/rpc/handlers/PayChanClaim.cpp index 44312ee336..b24a241147 100644 --- a/src/xrpld/rpc/handlers/PayChanClaim.cpp +++ b/src/xrpld/rpc/handlers/PayChanClaim.cpp @@ -29,8 +29,10 @@ doChannelAuthorize(RPC::JsonContext& context) auto const& params(context.params); for (auto const& p : {jss::channel_id, jss::amount}) + { if (!params.isMember(p)) return RPC::missing_field_error(p); + } // Compatibility if a key type isn't specified. If it is, the // keypairForSignature code will validate parameters and return @@ -92,8 +94,10 @@ doChannelVerify(RPC::JsonContext& context) { auto const& params(context.params); for (auto const& p : {jss::public_key, jss::channel_id, jss::amount, jss::signature}) + { if (!params.isMember(p)) return RPC::missing_field_error(p); + } std::optional pk; { @@ -125,7 +129,7 @@ doChannelVerify(RPC::JsonContext& context) std::uint64_t const drops = *optDrops; auto sig = strUnHex(params[jss::signature].asString()); - if (!sig || !sig->size()) + if (!sig || sig->empty()) return rpcError(rpcINVALID_PARAMS); Serializer msg; diff --git a/src/xrpld/rpc/handlers/Peers.cpp b/src/xrpld/rpc/handlers/Peers.cpp index 1be136a5f8..b21efc01fb 100644 --- a/src/xrpld/rpc/handlers/Peers.cpp +++ b/src/xrpld/rpc/handlers/Peers.cpp @@ -27,9 +27,13 @@ doPeers(RPC::JsonContext& context) auto const s = p[jss::track].asString(); if (s == "diverged") + { p["sanity"] = "insane"; + } else if (s == "unknown") + { p["sanity"] = "unknown"; + } } } } @@ -53,8 +57,10 @@ doPeers(RPC::JsonContext& context) json[jss::fee] = static_cast(node.getLoadFee()) / ref; if (node.getReportTime() != NetClock::time_point{}) + { json[jss::age] = (node.getReportTime() >= now) ? 0 : (now - node.getReportTime()).count(); + } }); return jvResult; diff --git a/src/xrpld/rpc/handlers/Ping.cpp b/src/xrpld/rpc/handlers/Ping.cpp index cc3c558cd9..4e9b18c4c9 100644 --- a/src/xrpld/rpc/handlers/Ping.cpp +++ b/src/xrpld/rpc/handlers/Ping.cpp @@ -22,7 +22,7 @@ doPing(RPC::JsonContext& context) case Role::IDENTIFIED: ret[jss::role] = "identified"; ret[jss::username] = std::string{context.headers.user}; - if (context.headers.forwardedFor.size()) + if (!context.headers.forwardedFor.empty()) ret[jss::ip] = std::string{context.headers.forwardedFor}; break; case Role::PROXY: diff --git a/src/xrpld/rpc/handlers/ServerDefinitions.cpp b/src/xrpld/rpc/handlers/ServerDefinitions.cpp index e153065ea9..24abd69a02 100644 --- a/src/xrpld/rpc/handlers/ServerDefinitions.cpp +++ b/src/xrpld/rpc/handlers/ServerDefinitions.cpp @@ -63,9 +63,11 @@ ServerDefinitions::translate(std::string const& inp) { if (contains("512") || contains("384") || contains("256") || contains("192") || contains("160") || contains("128")) + { return replace("UINT", "Hash"); - else - return replace("UINT", "UInt"); + } + + return replace("UINT", "UInt"); } static std::unordered_map const replacements{ @@ -102,7 +104,9 @@ ServerDefinitions::translate(std::string const& inp) out += token; } else + { out += token; + } if (pos == inpToProcess.size()) break; inpToProcess = inpToProcess.substr(pos + 1); @@ -217,7 +221,7 @@ ServerDefinitions::ServerDefinitions() : defs_{Json::objectValue} for (auto const& [code, field] : xrpl::SField::getKnownCodeToField()) { - if (field->fieldName == "") + if (field->fieldName.empty()) continue; Json::Value innerObj = Json::objectValue; diff --git a/src/xrpld/rpc/handlers/Submit.cpp b/src/xrpld/rpc/handlers/Submit.cpp index b8cca3670a..cac7259a00 100644 --- a/src/xrpld/rpc/handlers/Submit.cpp +++ b/src/xrpld/rpc/handlers/Submit.cpp @@ -55,7 +55,7 @@ doSubmit(RPC::JsonContext& context) auto ret = strUnHex(context.params[jss::tx_blob].asString()); - if (!ret || !ret->size()) + if (!ret || ret->empty()) return rpcError(rpcINVALID_PARAMS); SerialIter sitTrans(makeSlice(*ret)); @@ -76,8 +76,10 @@ doSubmit(RPC::JsonContext& context) { if (!context.app.checkSigs()) + { forceValidity( context.app.getHashRouter(), stTx->getTransactionID(), Validity::SigGoodOnly); + } auto [validity, reason] = checkValidity( context.app.getHashRouter(), *stTx, context.ledgerMaster.getCurrentLedger()->rules()); if (validity != Validity::Valid) diff --git a/src/xrpld/rpc/handlers/Subscribe.cpp b/src/xrpld/rpc/handlers/Subscribe.cpp index 8fbf5a917e..6e8d9dbaa3 100644 --- a/src/xrpld/rpc/handlers/Subscribe.cpp +++ b/src/xrpld/rpc/handlers/Subscribe.cpp @@ -281,10 +281,8 @@ doSubscribe(RPC::JsonContext& context) { return rpcError(rpcDOMAIN_MALFORMED); } - else - { - book.domain = domain; - } + + book.domain = domain; } if (!isConsistent(book)) diff --git a/src/xrpld/rpc/handlers/TransactionEntry.cpp b/src/xrpld/rpc/handlers/TransactionEntry.cpp index 8cd1120aad..36f53130fa 100644 --- a/src/xrpld/rpc/handlers/TransactionEntry.cpp +++ b/src/xrpld/rpc/handlers/TransactionEntry.cpp @@ -59,8 +59,10 @@ doTransactionEntry(RPC::JsonContext& context) jvResult[jss::hash] = to_string(sttx->getTransactionID()); if (!lpLedger->open()) + { jvResult[jss::ledger_hash] = to_string(context.ledgerMaster.getHashBySeq(lpLedger->seq())); + } bool const validated = context.ledgerMaster.isValidated(*lpLedger); @@ -73,7 +75,9 @@ doTransactionEntry(RPC::JsonContext& context) } } else + { jvResult[jss::tx_json] = sttx->getJson(JsonOptions::none); + } RPC::insertDeliverMax(jvResult[jss::tx_json], sttx->getTxnType(), context.apiVersion); diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index a34c1f1a2e..482b7e3bf1 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -153,7 +153,7 @@ doTxHelp(RPC::Context& context, TxArgs args) uint32_t netID = context.app.getNetworkIDService().getNetworkID(); if (txnIdx <= 0xFFFFU && netID < 0xFFFFU && lgrSeq < 0x0FFF'FFFFUL) - result.ctid = RPC::encodeCTID(lgrSeq, (uint32_t)txnIdx, (uint32_t)netID); + result.ctid = RPC::encodeCTID(lgrSeq, txnIdx, netID); } } @@ -192,7 +192,9 @@ populateJsonResponse( constexpr auto optionsJson = JsonOptions::include_date | JsonOptions::disable_API_prior_V2; if (args.binary) + { response[jss::tx_blob] = result.txn->getJson(optionsJson, true); + } else { response[jss::tx_json] = result.txn->getJson(optionsJson); @@ -258,8 +260,10 @@ doTxJson(RPC::JsonContext& context) TxArgs args; if (context.params.isMember(jss::transaction) && context.params.isMember(jss::ctid)) + { // specifying both is ambiguous return rpcError(rpcINVALID_PARAMS); + } if (context.params.isMember(jss::transaction)) { @@ -286,7 +290,9 @@ doTxJson(RPC::JsonContext& context) args.ctid = {lgr_seq, txn_idx}; } else + { return rpcError(rpcINVALID_PARAMS); + } args.binary = context.params.isMember(jss::binary) && context.params[jss::binary].asBool(); diff --git a/src/xrpld/rpc/handlers/Unsubscribe.cpp b/src/xrpld/rpc/handlers/Unsubscribe.cpp index 15da0d1d6a..824d57203c 100644 --- a/src/xrpld/rpc/handlers/Unsubscribe.cpp +++ b/src/xrpld/rpc/handlers/Unsubscribe.cpp @@ -165,8 +165,7 @@ doUnsubscribe(RPC::JsonContext& context) return rpcError(rpcSRC_CUR_MALFORMED); } // Parse optional issuer. - else if ( - ((taker_pays.isMember(jss::issuer)) && + if (((taker_pays.isMember(jss::issuer)) && (!taker_pays[jss::issuer].isString() || !to_issuer(book.in.account, taker_pays[jss::issuer].asString()))) // Don't allow illegal issuers. @@ -186,8 +185,7 @@ doUnsubscribe(RPC::JsonContext& context) return rpcError(rpcDST_AMT_MALFORMED); } // Parse optional issuer. - else if ( - ((taker_gets.isMember(jss::issuer)) && + if (((taker_gets.isMember(jss::issuer)) && (!taker_gets[jss::issuer].isString() || !to_issuer(book.out.account, taker_gets[jss::issuer].asString()))) // Don't allow illegal issuers. @@ -211,10 +209,8 @@ doUnsubscribe(RPC::JsonContext& context) { return rpcError(rpcDOMAIN_MALFORMED); } - else - { - book.domain = domain; - } + + book.domain = domain; } context.netOps.unsubBook(ispSub->getSeq(), book); diff --git a/src/xrpld/rpc/handlers/VaultInfo.cpp b/src/xrpld/rpc/handlers/VaultInfo.cpp index b17a16cc4a..4a704e0b0b 100644 --- a/src/xrpld/rpc/handlers/VaultInfo.cpp +++ b/src/xrpld/rpc/handlers/VaultInfo.cpp @@ -35,8 +35,7 @@ parseVault(Json::Value const& params, Json::Value& jvResult) RPC::inject_error(rpcACT_MALFORMED, jvResult); return std::nullopt; } - else if ( - !(params[jss::seq].isInt() || params[jss::seq].isUInt()) || + if (!(params[jss::seq].isInt() || params[jss::seq].isUInt()) || params[jss::seq].asDouble() <= 0.0 || params[jss::seq].asDouble() > double(Json::Value::maxUInt)) { diff --git a/src/xrpld/rpc/handlers/WalletPropose.cpp b/src/xrpld/rpc/handlers/WalletPropose.cpp index 273d829670..a5005ce701 100644 --- a/src/xrpld/rpc/handlers/WalletPropose.cpp +++ b/src/xrpld/rpc/handlers/WalletPropose.cpp @@ -76,9 +76,13 @@ walletPropose(Json::Value const& params) // to detect such keys to avoid user confusion. { if (params.isMember(jss::passphrase)) + { seed = RPC::parseRippleLibSeed(params[jss::passphrase]); + } else if (params.isMember(jss::seed)) + { seed = RPC::parseRippleLibSeed(params[jss::seed]); + } if (seed) { @@ -142,15 +146,19 @@ walletPropose(Json::Value const& params) // 80 bits of entropy isn't bad, but it's better to // err on the side of caution and be conservative. if (estimate_entropy(passphrase) < 80.0) + { obj[jss::warning] = "This wallet was generated using a user-supplied " "passphrase that has low entropy and is vulnerable " "to brute-force attacks."; + } else + { obj[jss::warning] = "This wallet was generated using a user-supplied " "passphrase. It may be vulnerable to brute-force " "attacks."; + } } } From 697fb64e8c833d189f7dbd1a12fdeea5b0327d6a Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Wed, 18 Mar 2026 17:46:27 +0000 Subject: [PATCH 46/60] 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 47/60] 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 48/60] 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 49/60] 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 50/60] 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 51/60] 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 52/60] 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 53/60] 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 54/60] 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 55/60] 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 56/60] 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 57/60] 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 58/60] 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 59/60] 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 60/60] 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