diff --git a/include/xrpl/protocol_autogen/ledger_entries/Loan.h b/include/xrpl/protocol_autogen/ledger_entries/Loan.h index 5d837736ec..4c6f05081c 100644 --- a/include/xrpl/protocol_autogen/ledger_entries/Loan.h +++ b/include/xrpl/protocol_autogen/ledger_entries/Loan.h @@ -68,14 +68,27 @@ public: } /** - * @brief Get sfOwnerNode (SoeRequired) - * @return The field value. + * @brief Get sfOwnerNode (SoeOptional) + * @return The field value, or std::nullopt if not present. */ [[nodiscard]] - SF_UINT64::type::value_type + protocol_autogen::Optional getOwnerNode() const { - return this->sle_->at(sfOwnerNode); + if (hasOwnerNode()) + return this->sle_->at(sfOwnerNode); + return std::nullopt; + } + + /** + * @brief Check if sfOwnerNode is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasOwnerNode() const + { + return this->sle_->isFieldPresent(sfOwnerNode); } /** @@ -578,7 +591,6 @@ 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. @@ -587,12 +599,11 @@ public: * @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) + LoanBuilder(std::decay_t const& previousTxnID,std::decay_t const& previousTxnLgrSeq,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); @@ -641,7 +652,7 @@ public: } /** - * @brief Set sfOwnerNode (SoeRequired) + * @brief Set sfOwnerNode (SoeOptional) * @return Reference to this builder for method chaining. */ LoanBuilder& diff --git a/include/xrpl/protocol_autogen/ledger_entries/Vault.h b/include/xrpl/protocol_autogen/ledger_entries/Vault.h index d1aaeb4ed8..8a0cac13b4 100644 --- a/include/xrpl/protocol_autogen/ledger_entries/Vault.h +++ b/include/xrpl/protocol_autogen/ledger_entries/Vault.h @@ -287,6 +287,30 @@ public: { return this->sle_->isFieldPresent(sfScale); } + + /** + * @brief Get sfAssetsReserved (SoeDefault) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getAssetsReserved() const + { + if (hasAssetsReserved()) + return this->sle_->at(sfAssetsReserved); + return std::nullopt; + } + + /** + * @brief Check if sfAssetsReserved is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasAssetsReserved() const + { + return this->sle_->isFieldPresent(sfAssetsReserved); + } }; /** @@ -506,6 +530,17 @@ public: return *this; } + /** + * @brief Set sfAssetsReserved (SoeDefault) + * @return Reference to this builder for method chaining. + */ + VaultBuilder& + setAssetsReserved(std::decay_t const& value) + { + object_[sfAssetsReserved] = value; + return *this; + } + /** * @brief Build and return the completed Vault wrapper. * @param index The ledger entry index. diff --git a/include/xrpl/protocol_autogen/transactions/LoanAccept.h b/include/xrpl/protocol_autogen/transactions/LoanAccept.h new file mode 100644 index 0000000000..44d984556d --- /dev/null +++ b/include/xrpl/protocol_autogen/transactions/LoanAccept.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 LoanAcceptBuilder; + +/** + * @brief Transaction: LoanAccept + * + * Type: ttLOAN_ACCEPT (83) + * Delegable: Delegation::NotDelegable + * Amendment: featureLendingProtocolV1_1 + * Privileges: NoPriv + * + * Immutable wrapper around STTx providing type-safe field access. + * Use LoanAcceptBuilder to construct new transactions. + */ +class LoanAccept : public TransactionBase +{ +public: + static constexpr xrpl::TxType txType = ttLOAN_ACCEPT; + + /** + * @brief Construct a LoanAccept transaction wrapper from an existing STTx object. + * @throws std::runtime_error if the transaction type doesn't match. + */ + explicit LoanAccept(std::shared_ptr tx) + : TransactionBase(std::move(tx)) + { + // Verify transaction type + if (tx_->getTxnType() != txType) + { + throw std::runtime_error("Invalid transaction type for LoanAccept"); + } + } + + // 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 LoanAccept transactions. + * + * Provides a fluent interface for constructing transactions with method chaining. + * Uses STObject internally for flexible transaction construction. + * Inherits common field setters from TransactionBuilderBase. + */ +class LoanAcceptBuilder : public TransactionBuilderBase +{ +public: + /** + * @brief Construct a new LoanAcceptBuilder 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. + */ + LoanAcceptBuilder(SF_ACCOUNT::type::value_type account, + std::decay_t const& loanID, std::optional sequence = std::nullopt, + std::optional fee = std::nullopt +) + : TransactionBuilderBase(ttLOAN_ACCEPT, account, sequence, fee) + { + setLoanID(loanID); + } + + /** + * @brief Construct a LoanAcceptBuilder from an existing STTx object. + * @param tx The existing transaction to copy from. + * @throws std::runtime_error if the transaction type doesn't match. + */ + LoanAcceptBuilder(std::shared_ptr tx) + { + if (tx->getTxnType() != ttLOAN_ACCEPT) + { + throw std::runtime_error("Invalid transaction type for LoanAcceptBuilder"); + } + object_ = *tx; + } + + /** @brief Transaction-specific field setters */ + + /** + * @brief Set sfLoanID (SoeRequired) + * @return Reference to this builder for method chaining. + */ + LoanAcceptBuilder& + setLoanID(std::decay_t const& value) + { + object_[sfLoanID] = value; + return *this; + } + + /** + * @brief Build and return the LoanAccept wrapper. + * @param publicKey The public key for signing. + * @param secretKey The secret key for signing. + * @return The constructed transaction wrapper. + */ + LoanAccept + build(PublicKey const& publicKey, SecretKey const& secretKey) + { + sign(publicKey, secretKey); + return LoanAccept{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 index 3fa3c905c2..aef9ef0e74 100644 --- a/include/xrpl/protocol_autogen/transactions/LoanSet.h +++ b/include/xrpl/protocol_autogen/transactions/LoanSet.h @@ -84,6 +84,32 @@ public: return this->tx_->isFieldPresent(sfData); } + /** + * @brief Get sfBorrower (SoeOptional) + * @return The field value, or std::nullopt if not present. + */ + [[nodiscard]] + protocol_autogen::Optional + getBorrower() const + { + if (hasBorrower()) + { + return this->tx_->at(sfBorrower); + } + return std::nullopt; + } + + /** + * @brief Check if sfBorrower is present. + * @return True if the field is present, false otherwise. + */ + [[nodiscard]] + bool + hasBorrower() const + { + return this->tx_->isFieldPresent(sfBorrower); + } + /** * @brief Get sfCounterparty (SoeOptional) * @return The field value, or std::nullopt if not present. @@ -524,6 +550,17 @@ public: return *this; } + /** + * @brief Set sfBorrower (SoeOptional) + * @return Reference to this builder for method chaining. + */ + LoanSetBuilder& + setBorrower(std::decay_t const& value) + { + object_[sfBorrower] = value; + return *this; + } + /** * @brief Set sfCounterparty (SoeOptional) * @return Reference to this builder for method chaining. diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp index 845a8337b9..10d1b56cad 100644 --- a/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/LoanTests.cpp @@ -51,7 +51,6 @@ TEST(LoanTests, BuilderSettersRoundTrip) LoanBuilder builder{ previousTxnIDValue, previousTxnLgrSeqValue, - ownerNodeValue, loanBrokerNodeValue, loanBrokerIDValue, loanSequenceValue, @@ -61,6 +60,7 @@ TEST(LoanTests, BuilderSettersRoundTrip) periodicPaymentValue }; + builder.setOwnerNode(ownerNodeValue); builder.setLoanOriginationFee(loanOriginationFeeValue); builder.setLoanServiceFee(loanServiceFeeValue); builder.setLatePaymentFee(latePaymentFeeValue); @@ -100,12 +100,6 @@ TEST(LoanTests, BuilderSettersRoundTrip) 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(); @@ -148,6 +142,14 @@ TEST(LoanTests, BuilderSettersRoundTrip) expectEqualField(expected, actual, "sfPeriodicPayment"); } + { + auto const& expected = ownerNodeValue; + auto const actualOpt = entry.getOwnerNode(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfOwnerNode"); + EXPECT_TRUE(entry.hasOwnerNode()); + } + { auto const& expected = loanOriginationFeeValue; auto const actualOpt = entry.getLoanOriginationFee(); @@ -384,16 +386,6 @@ TEST(LoanTests, BuilderFromSleRoundTrip) 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; @@ -464,6 +456,19 @@ TEST(LoanTests, BuilderFromSleRoundTrip) expectEqualField(expected, fromBuilder, "sfPeriodicPayment"); } + { + auto const& expected = ownerNodeValue; + + auto const fromSleOpt = entryFromSle.getOwnerNode(); + auto const fromBuilderOpt = entryFromBuilder.getOwnerNode(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfOwnerNode"); + expectEqualField(expected, *fromBuilderOpt, "sfOwnerNode"); + } + { auto const& expected = loanOriginationFeeValue; @@ -732,7 +737,6 @@ TEST(LoanTests, OptionalFieldsReturnNullopt) 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(); @@ -744,7 +748,6 @@ TEST(LoanTests, OptionalFieldsReturnNullopt) LoanBuilder builder{ previousTxnIDValue, previousTxnLgrSeqValue, - ownerNodeValue, loanBrokerNodeValue, loanBrokerIDValue, loanSequenceValue, @@ -757,6 +760,8 @@ TEST(LoanTests, OptionalFieldsReturnNullopt) auto const entry = builder.build(index); // Verify optional fields are not present + EXPECT_FALSE(entry.hasOwnerNode()); + EXPECT_FALSE(entry.getOwnerNode().has_value()); EXPECT_FALSE(entry.hasLoanOriginationFee()); EXPECT_FALSE(entry.getLoanOriginationFee().has_value()); EXPECT_FALSE(entry.hasLoanServiceFee()); diff --git a/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp b/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp index 2697924d37..235e681c46 100644 --- a/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp +++ b/src/tests/libxrpl/protocol_autogen/ledger_entries/VaultTests.cpp @@ -35,6 +35,7 @@ TEST(VaultTests, BuilderSettersRoundTrip) auto const shareMPTIDValue = canonical_UINT192(); auto const withdrawalPolicyValue = canonical_UINT8(); auto const scaleValue = canonical_UINT8(); + auto const assetsReservedValue = canonical_NUMBER(); VaultBuilder builder{ previousTxnIDValue, @@ -54,6 +55,7 @@ TEST(VaultTests, BuilderSettersRoundTrip) builder.setAssetsMaximum(assetsMaximumValue); builder.setLossUnrealized(lossUnrealizedValue); builder.setScale(scaleValue); + builder.setAssetsReserved(assetsReservedValue); builder.setLedgerIndex(index); builder.setFlags(0x1u); @@ -166,6 +168,14 @@ TEST(VaultTests, BuilderSettersRoundTrip) EXPECT_TRUE(entry.hasScale()); } + { + auto const& expected = assetsReservedValue; + auto const actualOpt = entry.getAssetsReserved(); + ASSERT_TRUE(actualOpt.has_value()); + expectEqualField(expected, *actualOpt, "sfAssetsReserved"); + EXPECT_TRUE(entry.hasAssetsReserved()); + } + EXPECT_TRUE(entry.hasLedgerIndex()); auto const ledgerIndex = entry.getLedgerIndex(); ASSERT_TRUE(ledgerIndex.has_value()); @@ -194,6 +204,7 @@ TEST(VaultTests, BuilderFromSleRoundTrip) auto const shareMPTIDValue = canonical_UINT192(); auto const withdrawalPolicyValue = canonical_UINT8(); auto const scaleValue = canonical_UINT8(); + auto const assetsReservedValue = canonical_NUMBER(); auto sle = std::make_shared(Vault::entryType, index); @@ -212,6 +223,7 @@ TEST(VaultTests, BuilderFromSleRoundTrip) sle->at(sfShareMPTID) = shareMPTIDValue; sle->at(sfWithdrawalPolicy) = withdrawalPolicyValue; sle->at(sfScale) = scaleValue; + sle->at(sfAssetsReserved) = assetsReservedValue; VaultBuilder builderFromSle{sle}; EXPECT_TRUE(builderFromSle.validate()); @@ -390,6 +402,19 @@ TEST(VaultTests, BuilderFromSleRoundTrip) expectEqualField(expected, *fromBuilderOpt, "sfScale"); } + { + auto const& expected = assetsReservedValue; + + auto const fromSleOpt = entryFromSle.getAssetsReserved(); + auto const fromBuilderOpt = entryFromBuilder.getAssetsReserved(); + + ASSERT_TRUE(fromSleOpt.has_value()); + ASSERT_TRUE(fromBuilderOpt.has_value()); + + expectEqualField(expected, *fromSleOpt, "sfAssetsReserved"); + expectEqualField(expected, *fromBuilderOpt, "sfAssetsReserved"); + } + EXPECT_EQ(entryFromSle.getKey(), index); EXPECT_EQ(entryFromBuilder.getKey(), index); } @@ -472,5 +497,7 @@ TEST(VaultTests, OptionalFieldsReturnNullopt) EXPECT_FALSE(entry.getLossUnrealized().has_value()); EXPECT_FALSE(entry.hasScale()); EXPECT_FALSE(entry.getScale().has_value()); + EXPECT_FALSE(entry.hasAssetsReserved()); + EXPECT_FALSE(entry.getAssetsReserved().has_value()); } } diff --git a/src/tests/libxrpl/protocol_autogen/transactions/LoanAcceptTests.cpp b/src/tests/libxrpl/protocol_autogen/transactions/LoanAcceptTests.cpp new file mode 100644 index 0000000000..83fc743955 --- /dev/null +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanAcceptTests.cpp @@ -0,0 +1,146 @@ +// Auto-generated unit tests for transaction LoanAccept + + +#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(TransactionsLoanAcceptTests, BuilderSettersRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::Secp256k1, generateSeed("testLoanAccept")); + + // 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(); + + LoanAcceptBuilder 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(TransactionsLoanAcceptTests, BuilderFromStTxRoundTrip) +{ + // Generate a deterministic keypair for signing + auto const [publicKey, secretKey] = + generateKeyPair(KeyType::Secp256k1, generateSeed("testLoanAcceptFromTx")); + + // 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 + LoanAcceptBuilder initialBuilder{ + accountValue, + loanIDValue, + sequenceValue, + feeValue + }; + + + auto initialTx = initialBuilder.build(publicKey, secretKey); + + // Create builder from existing STTx + LoanAcceptBuilder 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(TransactionsLoanAcceptTests, 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(LoanAccept{wrongTx.getSTTx()}, std::runtime_error); +} + +// 4) Verify builder throws when constructed from wrong transaction type. +TEST(TransactionsLoanAcceptTests, 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(LoanAcceptBuilder{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 index 8774a38a3b..2c177d489f 100644 --- a/src/tests/libxrpl/protocol_autogen/transactions/LoanSetTests.cpp +++ b/src/tests/libxrpl/protocol_autogen/transactions/LoanSetTests.cpp @@ -31,6 +31,7 @@ TEST(TransactionsLoanSetTests, BuilderSettersRoundTrip) // Transaction-specific field values auto const loanBrokerIDValue = canonical_UINT256(); auto const dataValue = canonical_VL(); + auto const borrowerValue = canonical_ACCOUNT(); auto const counterpartyValue = canonical_ACCOUNT(); auto const counterpartySignatureValue = canonical_OBJECT(); auto const loanOriginationFeeValue = canonical_NUMBER(); @@ -57,6 +58,7 @@ TEST(TransactionsLoanSetTests, BuilderSettersRoundTrip) // Set optional fields builder.setData(dataValue); + builder.setBorrower(borrowerValue); builder.setCounterparty(counterpartyValue); builder.setCounterpartySignature(counterpartySignatureValue); builder.setLoanOriginationFee(loanOriginationFeeValue); @@ -108,6 +110,14 @@ TEST(TransactionsLoanSetTests, BuilderSettersRoundTrip) EXPECT_TRUE(tx.hasData()); } + { + auto const& expected = borrowerValue; + auto const actualOpt = tx.getBorrower(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBorrower should be present"; + expectEqualField(expected, *actualOpt, "sfBorrower"); + EXPECT_TRUE(tx.hasBorrower()); + } + { auto const& expected = counterpartyValue; auto const actualOpt = tx.getCounterparty(); @@ -238,6 +248,7 @@ TEST(TransactionsLoanSetTests, BuilderFromStTxRoundTrip) // Transaction-specific field values auto const loanBrokerIDValue = canonical_UINT256(); auto const dataValue = canonical_VL(); + auto const borrowerValue = canonical_ACCOUNT(); auto const counterpartyValue = canonical_ACCOUNT(); auto const counterpartySignatureValue = canonical_OBJECT(); auto const loanOriginationFeeValue = canonical_NUMBER(); @@ -264,6 +275,7 @@ TEST(TransactionsLoanSetTests, BuilderFromStTxRoundTrip) }; initialBuilder.setData(dataValue); + initialBuilder.setBorrower(borrowerValue); initialBuilder.setCounterparty(counterpartyValue); initialBuilder.setCounterpartySignature(counterpartySignatureValue); initialBuilder.setLoanOriginationFee(loanOriginationFeeValue); @@ -315,6 +327,13 @@ TEST(TransactionsLoanSetTests, BuilderFromStTxRoundTrip) expectEqualField(expected, *actualOpt, "sfData"); } + { + auto const& expected = borrowerValue; + auto const actualOpt = rebuiltTx.getBorrower(); + ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfBorrower should be present"; + expectEqualField(expected, *actualOpt, "sfBorrower"); + } + { auto const& expected = counterpartyValue; auto const actualOpt = rebuiltTx.getCounterparty(); @@ -474,6 +493,8 @@ TEST(TransactionsLoanSetTests, OptionalFieldsReturnNullopt) // Verify optional fields are not present EXPECT_FALSE(tx.hasData()); EXPECT_FALSE(tx.getData().has_value()); + EXPECT_FALSE(tx.hasBorrower()); + EXPECT_FALSE(tx.getBorrower().has_value()); EXPECT_FALSE(tx.hasCounterparty()); EXPECT_FALSE(tx.getCounterparty().has_value()); EXPECT_FALSE(tx.hasCounterpartySignature());