#include "util/TestObject.hpp" #include "data/DBHelpers.hpp" #include "data/Types.hpp" #include "util/AccountUtils.hpp" #include "util/Assert.hpp" #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 #include #include #include namespace { constexpr auto kINDEX1 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC"; ripple::Slice const kSLICE("test", 4); } // namespace ripple::AccountID getAccountIdWithString(std::string_view id) { return util::parseBase58Wrapper(std::string(id)).value(); } ripple::uint256 getAccountKey(std::string_view id) { return ripple::keylet::account(getAccountIdWithString(id)).key; } ripple::uint256 getAccountKey(ripple::AccountID const& acc) { return ripple::keylet::account(acc).key; } ripple::LedgerHeader createLedgerHeader( std::string_view ledgerHash, ripple::LedgerIndex seq, std::optional age ) { using namespace std::chrono; auto ledgerHeader = ripple::LedgerHeader(); ledgerHeader.hash = ripple::uint256{ledgerHash}; ledgerHeader.seq = seq; if (age) { // Note: be cautious of using age values close to each other as the underlying NetClock // precision is seconds and the small time difference may lead to comparison bugs auto const now = duration_cast(system_clock::now().time_since_epoch()); auto const closeTime = (now - seconds{age.value()}).count() - kRIPPLE_EPOCH_START; ledgerHeader.closeTime = ripple::NetClock::time_point{seconds{closeTime}}; } return ledgerHeader; } ripple::LedgerHeader createLedgerHeaderWithUnixTime( std::string_view ledgerHash, ripple::LedgerIndex seq, uint64_t closeTimeUnixStamp ) { using namespace std::chrono; auto ledgerHeader = ripple::LedgerHeader(); ledgerHeader.hash = ripple::uint256{ledgerHash}; ledgerHeader.seq = seq; auto const closeTime = closeTimeUnixStamp - seconds{kRIPPLE_EPOCH_START}.count(); ledgerHeader.closeTime = ripple::NetClock::time_point{seconds{closeTime}}; return ledgerHeader; } ripple::STObject createLegacyFeeSettingLedgerObject( uint64_t base, uint32_t reserveInc, uint32_t reserveBase, uint32_t refFeeUnit, uint32_t flag ) { ripple::STObject obj(ripple::sfFee); obj.setFieldU16(ripple::sfLedgerEntryType, ripple::ltFEE_SETTINGS); obj.setFieldU64(ripple::sfBaseFee, base); obj.setFieldU32(ripple::sfReserveIncrement, reserveInc); obj.setFieldU32(ripple::sfReserveBase, reserveBase); obj.setFieldU32(ripple::sfReferenceFeeUnits, refFeeUnit); obj.setFieldU32(ripple::sfFlags, flag); return obj; } ripple::STObject createFeeSettingLedgerObject( ripple::STAmount base, ripple::STAmount reserveInc, ripple::STAmount reserveBase, uint32_t flag ) { ripple::STObject obj(ripple::sfFee); obj.setFieldU16(ripple::sfLedgerEntryType, ripple::ltFEE_SETTINGS); obj.setFieldAmount(ripple::sfBaseFeeDrops, base); obj.setFieldAmount(ripple::sfReserveBaseDrops, reserveBase); obj.setFieldAmount(ripple::sfReserveIncrementDrops, reserveInc); obj.setFieldU32(ripple::sfFlags, flag); return obj; } ripple::Blob createLegacyFeeSettingBlob( uint64_t base, uint32_t reserveInc, uint32_t reserveBase, uint32_t refFeeUnit, uint32_t flag ) { auto lo = createLegacyFeeSettingLedgerObject(base, reserveInc, reserveBase, refFeeUnit, flag); return lo.getSerializer().peekData(); } ripple::Blob createFeeSettingBlob( ripple::STAmount base, ripple::STAmount reserveInc, ripple::STAmount reserveBase, uint32_t flag ) { auto lo = createFeeSettingLedgerObject(base, reserveInc, reserveBase, flag); return lo.getSerializer().peekData(); } ripple::STObject createPaymentTransactionObject( std::string_view accountId1, std::string_view accountId2, int amount, int fee, uint32_t seq ) { ripple::STObject obj(ripple::sfTransaction); obj.setFieldU16(ripple::sfTransactionType, ripple::ttPAYMENT); auto account = util::parseBase58Wrapper(std::string(accountId1)); obj.setAccountID(ripple::sfAccount, account.value()); obj.setFieldAmount(ripple::sfAmount, ripple::STAmount(amount, false)); obj.setFieldAmount(ripple::sfFee, ripple::STAmount(fee, false)); auto account2 = util::parseBase58Wrapper(std::string(accountId2)); obj.setAccountID(ripple::sfDestination, account2.value()); obj.setFieldU32(ripple::sfSequence, seq); obj.setFieldVL(ripple::sfSigningPubKey, kSLICE); return obj; } ripple::STObject createPaymentTransactionMetaObject( std::string_view accountId1, std::string_view accountId2, int finalBalance1, int finalBalance2, uint32_t transactionIndex ) { ripple::STObject finalFields(ripple::sfFinalFields); finalFields.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId1)); finalFields.setFieldAmount(ripple::sfBalance, ripple::STAmount(finalBalance1)); ripple::STObject finalFields2(ripple::sfFinalFields); finalFields2.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId2)); finalFields2.setFieldAmount(ripple::sfBalance, ripple::STAmount(finalBalance2)); ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{2}; ripple::STObject node(ripple::sfModifiedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT); node.emplace_back(std::move(finalFields)); metaArray.push_back(node); ripple::STObject node2(ripple::sfModifiedNode); node2.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT); node2.emplace_back(std::move(finalFields2)); metaArray.push_back(node2); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, transactionIndex); return metaObj; } ripple::STObject createDidObject( std::string_view accountId, std::string_view didDoc, std::string_view uri, std::string_view data ) { ripple::STObject did(ripple::sfLedgerEntry); did.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); did.setFieldU16(ripple::sfLedgerEntryType, ripple::ltDID); did.setFieldU32(ripple::sfFlags, 0); did.setFieldU64(ripple::sfOwnerNode, 0); did.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); did.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); ripple::Slice const sliceDoc(didDoc.data(), didDoc.size()); did.setFieldVL(ripple::sfDIDDocument, sliceDoc); ripple::Slice const sliceUri(uri.data(), uri.size()); did.setFieldVL(ripple::sfURI, sliceUri); ripple::Slice const sliceData(data.data(), data.size()); did.setFieldVL(ripple::sfData, sliceData); return did; } ripple::STObject createAccountRootObject( std::string_view accountId, uint32_t flag, uint32_t seq, int balance, uint32_t ownerCount, std::string_view previousTxnID, uint32_t previousTxnSeq, uint32_t transferRate, std::optional ammID ) { ripple::STObject accountRoot(ripple::sfAccount); accountRoot.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT); accountRoot.setFieldU32(ripple::sfFlags, flag); accountRoot.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); accountRoot.setFieldU32(ripple::sfSequence, seq); accountRoot.setFieldAmount(ripple::sfBalance, ripple::STAmount(balance, false)); accountRoot.setFieldU32(ripple::sfOwnerCount, ownerCount); accountRoot.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{previousTxnID}); accountRoot.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxnSeq); accountRoot.setFieldU32(ripple::sfTransferRate, transferRate); if (ammID) accountRoot.setFieldH256(ripple::sfAMMID, *ammID); return accountRoot; } ripple::STObject createCreateOfferTransactionObject( std::string_view accountId, int fee, uint32_t seq, std::string_view currency, std::string_view issuer, int takerGets, int takerPays, bool reverse ) { ripple::STObject obj(ripple::sfTransaction); obj.setFieldU16(ripple::sfTransactionType, ripple::ttOFFER_CREATE); auto account = util::parseBase58Wrapper(std::string(accountId)); obj.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); obj.setFieldAmount(ripple::sfFee, amount); obj.setFieldU32(ripple::sfSequence, seq); // add amount ripple::Issue const issue1( ripple::Currency{currency}, util::parseBase58Wrapper(std::string(issuer)).value() ); if (reverse) { obj.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, takerGets)); obj.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(takerPays, false)); } else { obj.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(issue1, takerGets)); obj.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(takerPays, false)); } auto key = "test"; ripple::Slice const slice(key, 4); obj.setFieldVL(ripple::sfSigningPubKey, slice); return obj; } ripple::Issue getIssue(std::string_view currency, std::string_view issuerId) { // standard currency if (currency.size() == 3) { return ripple::Issue( ripple::to_currency(std::string(currency)), util::parseBase58Wrapper(std::string(issuerId)).value() ); } return ripple::Issue( ripple::Currency{currency}, util::parseBase58Wrapper(std::string(issuerId)).value() ); } ripple::STObject createMetaDataForBookChange( std::string_view currency, std::string_view issueId, uint32_t transactionIndex, int finalTakerGets, int previousTakerGets, int finalTakerPays, int previousTakerPays, std::optional domain ) { ripple::STObject finalFields(ripple::sfFinalFields); ripple::Issue const issue1 = getIssue(currency, issueId); finalFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, finalTakerPays)); finalFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(finalTakerGets, false)); if (domain.has_value()) finalFields.setFieldH256(ripple::sfDomainID, ripple::uint256{*domain}); ripple::STObject previousFields(ripple::sfPreviousFields); previousFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, previousTakerPays)); previousFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(previousTakerGets, false)); ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfModifiedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltOFFER); node.emplace_back(std::move(finalFields)); node.emplace_back(std::move(previousFields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, transactionIndex); return metaObj; } ripple::STObject createMetaDataForCreateOffer( std::string_view currency, std::string_view issueId, uint32_t transactionIndex, int finalTakerGets, int finalTakerPays, bool reverse ) { ripple::STObject finalFields(ripple::sfNewFields); ripple::Issue const issue1 = getIssue(currency, issueId); if (reverse) { finalFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(issue1, finalTakerPays)); finalFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(finalTakerGets, false)); } else { finalFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, finalTakerPays)); finalFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(finalTakerGets, false)); } ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfCreatedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltOFFER); node.emplace_back(std::move(finalFields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, transactionIndex); return metaObj; } ripple::STObject createMetaDataForCancelOffer( std::string_view currency, std::string_view issueId, uint32_t transactionIndex, int finalTakerGets, int finalTakerPays ) { ripple::STObject finalFields(ripple::sfFinalFields); ripple::Issue const issue1 = getIssue(currency, issueId); finalFields.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, finalTakerPays)); finalFields.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(finalTakerGets, false)); ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfDeletedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltOFFER); node.emplace_back(std::move(finalFields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, transactionIndex); return metaObj; } ripple::STObject createOwnerDirLedgerObject(std::vector indexes, std::string_view rootIndex) { ripple::STObject ownerDir(ripple::sfLedgerEntry); ownerDir.setFieldU16(ripple::sfLedgerEntryType, ripple::ltDIR_NODE); ownerDir.setFieldV256(ripple::sfIndexes, ripple::STVector256{indexes}); ownerDir.setFieldH256(ripple::sfRootIndex, ripple::uint256{rootIndex}); ownerDir.setFieldU32(ripple::sfFlags, 0); return ownerDir; } ripple::STObject createPaymentChannelLedgerObject( std::string_view accountId, std::string_view destId, int amount, int balance, uint32_t settleDelay, std::string_view previousTxnId, uint32_t previousTxnSeq ) { ripple::STObject channel(ripple::sfLedgerEntry); channel.setFieldU16(ripple::sfLedgerEntryType, ripple::ltPAYCHAN); channel.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); channel.setAccountID(ripple::sfDestination, getAccountIdWithString(destId)); channel.setFieldAmount(ripple::sfAmount, ripple::STAmount(amount, false)); channel.setFieldAmount(ripple::sfBalance, ripple::STAmount(balance, false)); channel.setFieldU32(ripple::sfSettleDelay, settleDelay); channel.setFieldU64(ripple::sfOwnerNode, 0); channel.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{previousTxnId}); channel.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxnSeq); channel.setFieldU32(ripple::sfFlags, 0); uint8_t key[33] = {0}; key[0] = 2; // KeyType::secp256k1 ripple::Slice const slice(key, 33); channel.setFieldVL(ripple::sfPublicKey, slice); return channel; } [[nodiscard]] ripple::STObject createRippleStateLedgerObject( std::string_view currency, std::string_view issuerId, int balance, std::string_view lowNodeAccountId, int lowLimit, std::string_view highNodeAccountId, int highLimit, std::string_view previousTxnId, uint32_t previousTxnSeq, uint32_t flag ) { auto line = ripple::STObject(ripple::sfLedgerEntry); line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); line.setFieldU32(ripple::sfFlags, flag); line.setFieldAmount(ripple::sfBalance, ripple::STAmount(getIssue(currency, issuerId), balance)); line.setFieldAmount( ripple::sfHighLimit, ripple::STAmount(getIssue(currency, highNodeAccountId), highLimit) ); line.setFieldAmount( ripple::sfLowLimit, ripple::STAmount(getIssue(currency, lowNodeAccountId), lowLimit) ); line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{previousTxnId}); line.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxnSeq); return line; } ripple::STObject createOfferLedgerObject( std::string_view account, int takerGets, int takerPays, std::string_view getsCurrency, std::string_view paysCurrency, std::string_view getsIssueId, std::string_view paysIssueId, std::string_view dirId, std::optional domain ) { ripple::STObject offer(ripple::sfLedgerEntry); offer.setFieldU16(ripple::sfLedgerEntryType, ripple::ltOFFER); offer.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); offer.setFieldU32(ripple::sfSequence, 0); offer.setFieldU32(ripple::sfFlags, 0); ripple::Issue const issue1 = getIssue(getsCurrency, getsIssueId); offer.setFieldAmount(ripple::sfTakerGets, ripple::STAmount(issue1, takerGets)); ripple::Issue const issue2 = getIssue(paysCurrency, paysIssueId); offer.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue2, takerPays)); offer.setFieldH256(ripple::sfBookDirectory, ripple::uint256{}); offer.setFieldU64(ripple::sfBookNode, 0); offer.setFieldU64(ripple::sfOwnerNode, 0); offer.setFieldH256(ripple::sfBookDirectory, ripple::uint256{dirId}); offer.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); offer.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); if (domain.has_value()) offer.setFieldH256(ripple::sfDomainID, ripple::uint256{*domain}); return offer; } ripple::STObject createTicketLedgerObject(std::string_view account, uint32_t sequence) { ripple::STObject ticket(ripple::sfLedgerEntry); ticket.setFieldU16(ripple::sfLedgerEntryType, ripple::ltTICKET); ticket.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); ticket.setFieldU32(ripple::sfFlags, 0); ticket.setFieldU64(ripple::sfOwnerNode, 0); ticket.setFieldU32(ripple::sfTicketSequence, sequence); ticket.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); ticket.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); return ticket; } ripple::STObject createEscrowLedgerObject(std::string_view account, std::string_view dest) { ripple::STObject escrow(ripple::sfLedgerEntry); escrow.setFieldU16(ripple::sfLedgerEntryType, ripple::ltESCROW); escrow.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); escrow.setAccountID(ripple::sfDestination, getAccountIdWithString(dest)); escrow.setFieldAmount(ripple::sfAmount, ripple::STAmount(0, false)); escrow.setFieldU64(ripple::sfOwnerNode, 0); escrow.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); escrow.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); escrow.setFieldU32(ripple::sfFlags, 0); return escrow; } ripple::STObject createCheckLedgerObject(std::string_view account, std::string_view dest) { ripple::STObject check(ripple::sfLedgerEntry); check.setFieldU16(ripple::sfLedgerEntryType, ripple::ltCHECK); check.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); check.setAccountID(ripple::sfDestination, getAccountIdWithString(dest)); check.setFieldU32(ripple::sfFlags, 0); check.setFieldU64(ripple::sfOwnerNode, 0); check.setFieldU64(ripple::sfDestinationNode, 0); check.setFieldAmount(ripple::sfSendMax, ripple::STAmount(0, false)); check.setFieldU32(ripple::sfSequence, 0); check.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); check.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); return check; } ripple::STObject createDepositPreauthLedgerObjectByAuth(std::string_view account, std::string_view auth) { ripple::STObject depositPreauth(ripple::sfLedgerEntry); depositPreauth.setFieldU16(ripple::sfLedgerEntryType, ripple::ltDEPOSIT_PREAUTH); depositPreauth.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); depositPreauth.setAccountID(ripple::sfAuthorize, getAccountIdWithString(auth)); depositPreauth.setFieldU32(ripple::sfFlags, 0); depositPreauth.setFieldU64(ripple::sfOwnerNode, 0); depositPreauth.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); depositPreauth.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); return depositPreauth; } ripple::STObject createDepositPreauthLedgerObjectByAuthCredentials( std::string_view account, std::string_view issuer, std::string_view credType ) { ripple::STObject depositPreauth(ripple::sfLedgerEntry); depositPreauth.setFieldU16(ripple::sfLedgerEntryType, ripple::ltDEPOSIT_PREAUTH); depositPreauth.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); depositPreauth.setFieldArray( ripple::sfAuthorizeCredentials, createAuthCredentialArray( std::vector{issuer}, std::vector{credType} ) ); depositPreauth.setFieldU32(ripple::sfFlags, 0); depositPreauth.setFieldU64(ripple::sfOwnerNode, 0); depositPreauth.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); depositPreauth.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); return depositPreauth; } data::NFT createNft( std::string_view tokenID, std::string_view account, ripple::LedgerIndex seq, ripple::Blob uri, bool isBurned ) { return data::NFT{ripple::uint256(tokenID), seq, getAccountIdWithString(account), uri, isBurned}; } ripple::STObject createNftBuyOffer(std::string_view tokenID, std::string_view account) { ripple::STObject offer(ripple::sfLedgerEntry); offer.setFieldH256(ripple::sfNFTokenID, ripple::uint256{tokenID}); offer.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_OFFER); offer.setFieldU32(ripple::sfFlags, 0u); offer.setFieldAmount(ripple::sfAmount, ripple::STAmount{123}); offer.setFieldU64(ripple::sfOwnerNode, 0ul); offer.setAccountID(ripple::sfOwner, getAccountIdWithString(account)); offer.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); offer.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0u); offer.setFieldU64(ripple::sfNFTokenOfferNode, 0ul); return offer; } ripple::STObject createNftSellOffer(std::string_view tokenID, std::string_view account) { ripple::STObject offer(ripple::sfLedgerEntry); offer.setFieldH256(ripple::sfNFTokenID, ripple::uint256{tokenID}); offer.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_OFFER); offer.setFieldU32(ripple::sfFlags, 0u); offer.setFieldAmount(ripple::sfAmount, ripple::STAmount{123}); offer.setFieldU64(ripple::sfOwnerNode, 0ul); offer.setAccountID(ripple::sfOwner, getAccountIdWithString(account)); offer.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); offer.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0u); offer.setFieldU64(ripple::sfNFTokenOfferNode, 0ul); return offer; } ripple::STObject createSignerLists(std::vector> const& signers) { auto signerlists = ripple::STObject(ripple::sfLedgerEntry); signerlists.setFieldU16(ripple::sfLedgerEntryType, ripple::ltSIGNER_LIST); signerlists.setFieldU32(ripple::sfFlags, 0); signerlists.setFieldU64(ripple::sfOwnerNode, 0); signerlists.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256()); signerlists.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); signerlists.setFieldU32(ripple::sfSignerListID, 0); uint32_t quorum = 0; ripple::STArray list; for (auto const& signer : signers) { auto entry = ripple::STObject(ripple::sfSignerEntry); entry.setAccountID(ripple::sfAccount, getAccountIdWithString(signer.first)); entry.setFieldU16(ripple::sfSignerWeight, signer.second); quorum += signer.second; list.push_back(std::move(entry)); } signerlists.setFieldU32(ripple::sfSignerQuorum, quorum); signerlists.setFieldArray(ripple::sfSignerEntries, list); return signerlists; } ripple::STObject createNftTokenPage( std::vector> const& tokens, std::optional previousPage ) { auto tokenPage = ripple::STObject(ripple::sfLedgerEntry); tokenPage.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); tokenPage.setFieldU32(ripple::sfFlags, 0); tokenPage.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256()); tokenPage.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); if (previousPage) tokenPage.setFieldH256(ripple::sfPreviousPageMin, *previousPage); ripple::STArray list; for (auto const& token : tokens) { auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{token.first.c_str()}); entry.setFieldVL(ripple::sfURI, ripple::Slice(token.second.c_str(), token.second.size())); list.push_back(std::move(entry)); } tokenPage.setFieldArray(ripple::sfNFTokens, list); return tokenPage; } data::TransactionAndMetadata createMintNftTxWithMetadata( std::string_view accountId, uint32_t seq, uint32_t fee, uint32_t nfTokenTaxon, std::string_view nftID ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_MINT); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); // required field for ttNFTOKEN_MINT tx.setFieldU32(ripple::sfNFTokenTaxon, nfTokenTaxon); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfModifiedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); ripple::STObject finalFields(ripple::sfFinalFields); ripple::STArray nftArray1{2}; // finalFields contain new NFT while previousFields does not auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); char const* url = "testurl"; entry.setFieldVL(ripple::sfURI, ripple::Slice(url, 7)); nftArray1.push_back(entry); auto entry2 = ripple::STObject(ripple::sfNFToken); entry2.setFieldH256(ripple::sfNFTokenID, ripple::uint256{kINDEX1}); entry2.setFieldVL(ripple::sfURI, ripple::Slice(url, 7)); nftArray1.push_back(entry2); finalFields.setFieldArray(ripple::sfNFTokens, nftArray1); nftArray1.erase(nftArray1.begin()); ripple::STObject previousFields(ripple::sfPreviousFields); previousFields.setFieldArray(ripple::sfNFTokens, nftArray1); node.emplace_back(std::move(finalFields)); node.emplace_back(std::move(previousFields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createMintNftTxWithMetadataOfCreatedNode( std::string_view accountId, uint32_t seq, uint32_t fee, uint32_t nfTokenTaxon, std::optional nftID, std::optional uri, std::optional pageIndex ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_MINT); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); // required field for ttNFTOKEN_MINT tx.setFieldU32(ripple::sfNFTokenTaxon, nfTokenTaxon); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); if (uri) tx.setFieldVL(ripple::sfURI, ripple::Slice(uri->data(), uri->size())); // meta ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfCreatedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); ripple::STObject newFields(ripple::sfNewFields); ripple::STArray nftArray1{1}; if (nftID) { // finalFields contain new NFT while previousFields does not auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{*nftID}); if (uri) entry.setFieldVL(ripple::sfURI, ripple::Slice(uri->data(), uri->size())); nftArray1.push_back(entry); } newFields.setFieldArray(ripple::sfNFTokens, nftArray1); node.emplace_back(std::move(newFields)); if (pageIndex) node.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{*pageIndex}); // add a ledger object ahead of nft page ripple::STObject node2(ripple::sfCreatedNode); node2.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT); metaArray.push_back(node2); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createNftModifyTxWithMetadata(std::string_view accountId, std::string_view nftID, ripple::Blob uri) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_MODIFY); auto account = ripple::parseBase58(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(10, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); tx.setFieldU32(ripple::sfSequence, 100); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); if (!uri.empty()) // sfURI should be absent if empty tx.setFieldVL(ripple::sfURI, uri); // meta ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfModifiedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); ripple::STObject finalFields(ripple::sfFinalFields); ripple::STArray nftArray1{1}; ripple::STArray nftArray2{1}; // finalFields contain new NFT while previousFields does not auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); if (!uri.empty()) entry.setFieldVL(ripple::sfURI, uri); nftArray1.push_back(entry); auto entry2 = ripple::STObject(ripple::sfNFToken); entry2.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); char const* url = "previous"; entry2.setFieldVL(ripple::sfURI, ripple::Slice(url, 7)); nftArray2.push_back(entry2); finalFields.setFieldArray(ripple::sfNFTokens, nftArray1); ripple::STObject previousFields(ripple::sfPreviousFields); previousFields.setFieldArray(ripple::sfNFTokens, nftArray2); node.emplace_back(std::move(finalFields)); node.emplace_back(std::move(previousFields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createNftBurnTxWithMetadataOfDeletedNode(std::string_view accountId, std::string_view nftID) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_BURN); auto account = getAccountIdWithString(accountId); tx.setAccountID(ripple::sfAccount, account); auto amount = ripple::STAmount(10, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); tx.setFieldU32(ripple::sfSequence, 100); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfDeletedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); // deleted node should contain finalFields ripple::STObject finalFields(ripple::sfFinalFields); ripple::STArray nftArray{1}; auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); nftArray.push_back(entry); finalFields.setFieldArray(ripple::sfNFTokens, nftArray); node.emplace_back(std::move(finalFields)); // add a ledger object ahead of nft page ripple::STObject node2(ripple::sfCreatedNode); node2.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT); metaArray.push_back(node2); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createNftBurnTxWithMetadataOfModifiedNode(std::string_view accountId, std::string_view nftID) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_BURN); auto account = getAccountIdWithString(accountId); tx.setAccountID(ripple::sfAccount, account); auto amount = ripple::STAmount(10, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); tx.setFieldU32(ripple::sfSequence, 100); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfModifiedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); ripple::STObject finalFields(ripple::sfFinalFields); ripple::STArray nftArray{1}; ripple::STObject previousFields(ripple::sfPreviousFields); auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftID}); nftArray.push_back(entry); previousFields.setFieldArray(ripple::sfNFTokens, nftArray); node.emplace_back(std::move(previousFields)); node.emplace_back(std::move(finalFields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createAcceptNftBuyerOfferTxWithMetadata( std::string_view accountId, uint32_t seq, uint32_t fee, std::string_view nftId, std::string_view offerId ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_ACCEPT_OFFER); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldH256(ripple::sfNFTokenBuyOffer, ripple::uint256{offerId}); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta // create deletedNode with ltNFTOKEN_OFFER ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfDeletedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_OFFER); ripple::STObject finalFields(ripple::sfFinalFields); finalFields.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftId}); // for buyer offer, the offer owner is the nft's new owner finalFields.setAccountID(ripple::sfOwner, account.value()); node.emplace_back(std::move(finalFields)); node.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{offerId}); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createAcceptNftSellerOfferTxWithMetadata( std::string_view accountId, uint32_t seq, uint32_t fee, std::string_view nftId, std::string_view offerId, std::string_view pageIndex, bool isNewPageCreated ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_ACCEPT_OFFER); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldH256(ripple::sfNFTokenSellOffer, ripple::uint256{offerId}); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta // create deletedNode with ltNFTOKEN_OFFER ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfDeletedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_OFFER); ripple::STObject finalFields(ripple::sfFinalFields); finalFields.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftId}); // offer owner is not the nft's new owner for seller offer, we need to create other nodes for // processing new owner finalFields.setAccountID(ripple::sfOwner, account.value()); node.emplace_back(finalFields); node.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{offerId}); metaArray.push_back(node); // new owner's nft page node changed: 1 new nft page node added 2 old nft page node modified if (isNewPageCreated) { ripple::STObject node2(ripple::sfCreatedNode); node2.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); ripple::STObject newFields(ripple::sfNewFields); ripple::STArray nftArray1{1}; auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftId}); nftArray1.push_back(entry); newFields.setFieldArray(ripple::sfNFTokens, nftArray1); node2.emplace_back(std::move(newFields)); node2.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{pageIndex}); metaArray.push_back(node2); } else { ripple::STObject node2(ripple::sfModifiedNode); node2.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_PAGE); ripple::STArray nftArray1{2}; // finalFields contain new NFT while previousFields does not auto entry = ripple::STObject(ripple::sfNFToken); entry.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftId}); nftArray1.push_back(entry); auto entry2 = ripple::STObject(ripple::sfNFToken); entry2.setFieldH256(ripple::sfNFTokenID, ripple::uint256{kINDEX1}); nftArray1.push_back(entry2); finalFields.setFieldArray(ripple::sfNFTokens, nftArray1); nftArray1.erase(nftArray1.begin()); ripple::STObject previousFields(ripple::sfPreviousFields); previousFields.setFieldArray(ripple::sfNFTokens, nftArray1); node2.emplace_back(std::move(finalFields)); node2.emplace_back(std::move(previousFields)); node2.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{pageIndex}); metaArray.push_back(node2); } metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } // NFTokenCancelOffer can be used to cancel multiple offers data::TransactionAndMetadata createCancelNftOffersTxWithMetadata( std::string_view accountId, uint32_t seq, uint32_t fee, std::vector const& nftOffers ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_CANCEL_OFFER); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldU32(ripple::sfSequence, seq); ripple::STVector256 offers; offers.resize(nftOffers.size()); std::ranges::transform(nftOffers, offers.begin(), [&](auto const& nftId) { return ripple::uint256{nftId.c_str()}; }); tx.setFieldV256(ripple::sfNFTokenOffers, offers); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta // create deletedNode with ltNFTOKEN_OFFER // reuse the offer id as nft id ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{nftOffers.size()}; for (auto const& nftId : nftOffers) { ripple::STObject node(ripple::sfDeletedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_OFFER); ripple::STObject finalFields(ripple::sfFinalFields); finalFields.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftId.c_str()}); node.emplace_back(std::move(finalFields)); metaArray.push_back(node); } metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createCreateNftOfferTxWithMetadata( std::string_view accountId, uint32_t seq, uint32_t fee, std::string_view nftId, std::uint32_t offerPrice, std::string_view offerId ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_CREATE_OFFER); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); auto price = ripple::STAmount(offerPrice, false); tx.setFieldAmount(ripple::sfAmount, price); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldH256(ripple::sfNFTokenID, ripple::uint256{nftId}); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); // meta // create createdNode with LedgerIndex ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(ripple::sfCreatedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltNFTOKEN_OFFER); node.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{offerId}); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } data::TransactionAndMetadata createOracleSetTxWithMetadata( std::string_view accountId, uint32_t seq, uint32_t fee, uint32_t docId, std::uint32_t lastUpdateTime, ripple::STArray priceDataSeries, std::string_view oracleIndex, bool created, std::string_view previousTxnId ) { // tx ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttORACLE_SET); auto account = util::parseBase58Wrapper(std::string(accountId)); tx.setAccountID(ripple::sfAccount, account.value()); auto amount = ripple::STAmount(fee, false); tx.setFieldAmount(ripple::sfFee, amount); tx.setFieldU32(ripple::sfLastUpdateTime, lastUpdateTime); tx.setFieldU32(ripple::sfOracleDocumentID, docId); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); tx.setFieldArray(ripple::sfPriceDataSeries, priceDataSeries); // meta ripple::STObject metaObj(ripple::sfTransactionMetaData); ripple::STArray metaArray{1}; ripple::STObject node(created ? ripple::sfCreatedNode : ripple::sfModifiedNode); node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltORACLE); node.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{oracleIndex}); node.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{previousTxnId}); ripple::STObject fields(created ? ripple::sfNewFields : ripple::sfFinalFields); fields.setFieldU32(ripple::sfOracleDocumentID, docId); fields.setFieldU32(ripple::sfLastUpdateTime, lastUpdateTime); fields.setFieldArray(ripple::sfPriceDataSeries, priceDataSeries); node.emplace_back(std::move(fields)); metaArray.push_back(node); metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } ripple::STObject createAmendmentsObject(std::vector const& enabledAmendments) { auto amendments = ripple::STObject(ripple::sfLedgerEntry); amendments.setFieldU16(ripple::sfLedgerEntryType, ripple::ltAMENDMENTS); amendments.setFieldU32(ripple::sfFlags, 0); ripple::STVector256 const list(enabledAmendments); amendments.setFieldV256(ripple::sfAmendments, list); return amendments; } ripple::STObject createBrokenAmendmentsObject() { auto amendments = ripple::STObject(ripple::sfLedgerEntry); amendments.setFieldU16(ripple::sfLedgerEntryType, ripple::ltAMENDMENTS); amendments.setFieldU32(ripple::sfFlags, 0); // Note: no sfAmendments present return amendments; } ripple::STObject createAmmObject( std::string_view accountId, std::string_view assetCurrency, std::string_view assetIssuer, std::string_view asset2Currency, std::string_view asset2Issuer, std::string_view lpTokenBalanceIssueCurrency, uint32_t lpTokenBalanceIssueAmount, uint16_t tradingFee, uint64_t ownerNode ) { auto amm = ripple::STObject(ripple::sfLedgerEntry); amm.setFieldU16(ripple::sfLedgerEntryType, ripple::ltAMM); amm.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); amm.setFieldU16(ripple::sfTradingFee, tradingFee); amm.setFieldU64(ripple::sfOwnerNode, ownerNode); amm.setFieldIssue( ripple::sfAsset, ripple::STIssue{ripple::sfAsset, getIssue(assetCurrency, assetIssuer)} ); amm.setFieldIssue( ripple::sfAsset2, ripple::STIssue{ripple::sfAsset2, getIssue(asset2Currency, asset2Issuer)} ); ripple::Issue const issue1( ripple::Currency{lpTokenBalanceIssueCurrency}, util::parseBase58Wrapper(std::string(accountId)).value() ); amm.setFieldAmount( ripple::sfLPTokenBalance, ripple::STAmount(issue1, lpTokenBalanceIssueAmount) ); amm.setFieldU32(ripple::sfFlags, 0); return amm; } ripple::STObject createBridgeObject( std::string_view accountId, std::string_view lockingDoor, std::string_view issuingDoor, std::string_view issuingCurrency, std::string_view issuingIssuer ) { auto bridge = ripple::STObject(ripple::sfLedgerEntry); bridge.setFieldU16(ripple::sfLedgerEntryType, ripple::ltBRIDGE); bridge.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); bridge.setFieldAmount(ripple::sfSignatureReward, ripple::STAmount(10, false)); bridge.setFieldU64(ripple::sfXChainClaimID, 100); bridge.setFieldU64(ripple::sfXChainAccountCreateCount, 100); bridge.setFieldU64(ripple::sfXChainAccountClaimCount, 100); bridge.setFieldU64(ripple::sfOwnerNode, 100); bridge.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); bridge.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); bridge.setFieldU32(ripple::sfFlags, 0); Json::Value lockingIssue; lockingIssue["currency"] = "XRP"; Json::Value issuingIssue; issuingIssue["currency"] = std::string(issuingCurrency); issuingIssue["issuer"] = std::string(issuingIssuer); bridge[ripple::sfXChainBridge] = ripple::STXChainBridge( getAccountIdWithString(lockingDoor), ripple::issueFromJson(lockingIssue), getAccountIdWithString(issuingDoor), ripple::issueFromJson(issuingIssue) ); bridge.setFieldU32(ripple::sfFlags, 0); return bridge; } ripple::STObject createChainOwnedClaimIdObject( std::string_view accountId, std::string_view lockingDoor, std::string_view issuingDoor, std::string_view issuingCurrency, std::string_view issuingIssuer, std::string_view otherChainSource ) { auto chainOwnedClaimID = ripple::STObject(ripple::sfLedgerEntry); chainOwnedClaimID.setFieldU16(ripple::sfLedgerEntryType, ripple::ltXCHAIN_OWNED_CLAIM_ID); chainOwnedClaimID.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); chainOwnedClaimID.setFieldAmount(ripple::sfSignatureReward, ripple::STAmount(10, false)); chainOwnedClaimID.setFieldU64(ripple::sfXChainClaimID, 100); chainOwnedClaimID.setFieldU64(ripple::sfOwnerNode, 100); chainOwnedClaimID.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); chainOwnedClaimID.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); chainOwnedClaimID.setFieldU32(ripple::sfFlags, 0); Json::Value lockingIssue; lockingIssue["currency"] = "XRP"; Json::Value issuingIssue; issuingIssue["currency"] = std::string(issuingCurrency); issuingIssue["issuer"] = std::string(issuingIssuer); chainOwnedClaimID[ripple::sfXChainBridge] = ripple::STXChainBridge( getAccountIdWithString(lockingDoor), ripple::issueFromJson(lockingIssue), getAccountIdWithString(issuingDoor), ripple::issueFromJson(issuingIssue) ); chainOwnedClaimID.setFieldU32(ripple::sfFlags, 0); chainOwnedClaimID.setAccountID( ripple::sfOtherChainSource, getAccountIdWithString(otherChainSource) ); chainOwnedClaimID.setFieldArray(ripple::sfXChainClaimAttestations, ripple::STArray{}); return chainOwnedClaimID; } ripple::STObject createChainOwnedCreateAccountClaimId( std::string_view accountId, std::string_view lockingDoor, std::string_view issuingDoor, std::string_view issuingCurrency, std::string_view issuingIssuer ) { auto chainOwnedCreateAccountClaimID = ripple::STObject(ripple::sfLedgerEntry); chainOwnedCreateAccountClaimID.setFieldU16( ripple::sfLedgerEntryType, ripple::ltXCHAIN_OWNED_CLAIM_ID ); chainOwnedCreateAccountClaimID.setAccountID( ripple::sfAccount, getAccountIdWithString(accountId) ); chainOwnedCreateAccountClaimID.setFieldU64(ripple::sfXChainAccountCreateCount, 100); chainOwnedCreateAccountClaimID.setFieldU64(ripple::sfOwnerNode, 100); chainOwnedCreateAccountClaimID.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); chainOwnedCreateAccountClaimID.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); chainOwnedCreateAccountClaimID.setFieldU32(ripple::sfFlags, 0); Json::Value lockingIssue; lockingIssue["currency"] = "XRP"; Json::Value issuingIssue; issuingIssue["currency"] = std::string(issuingCurrency); issuingIssue["issuer"] = std::string(issuingIssuer); chainOwnedCreateAccountClaimID[ripple::sfXChainBridge] = ripple::STXChainBridge( getAccountIdWithString(lockingDoor), ripple::issueFromJson(lockingIssue), getAccountIdWithString(issuingDoor), ripple::issueFromJson(issuingIssue) ); chainOwnedCreateAccountClaimID.setFieldU32(ripple::sfFlags, 0); chainOwnedCreateAccountClaimID.setFieldArray( ripple::sfXChainCreateAccountAttestations, ripple::STArray{} ); return chainOwnedCreateAccountClaimID; } void ammAddVoteSlot( ripple::STObject& amm, ripple::AccountID const& accountId, uint16_t tradingFee, uint32_t voteWeight ) { if (!amm.isFieldPresent(ripple::sfVoteSlots)) amm.setFieldArray(ripple::sfVoteSlots, ripple::STArray{}); auto& arr = amm.peekFieldArray(ripple::sfVoteSlots); auto slot = ripple::STObject(ripple::sfVoteEntry); slot.setAccountID(ripple::sfAccount, accountId); slot.setFieldU16(ripple::sfTradingFee, tradingFee); slot.setFieldU32(ripple::sfVoteWeight, voteWeight); arr.push_back(slot); } void ammSetAuctionSlot( ripple::STObject& amm, ripple::AccountID const& accountId, ripple::STAmount price, uint16_t discountedFee, uint32_t expiration, std::vector const& authAccounts ) { ASSERT(expiration >= 24 * 3600, "Expiration must be at least 24 hours"); if (!amm.isFieldPresent(ripple::sfAuctionSlot)) amm.makeFieldPresent(ripple::sfAuctionSlot); auto& auctionSlot = amm.peekFieldObject(ripple::sfAuctionSlot); auctionSlot.setAccountID(ripple::sfAccount, accountId); auctionSlot.setFieldAmount(ripple::sfPrice, price); auctionSlot.setFieldU16(ripple::sfDiscountedFee, discountedFee); auctionSlot.setFieldU32(ripple::sfExpiration, expiration); if (not authAccounts.empty()) { ripple::STArray accounts; for (auto const& acc : authAccounts) { ripple::STObject authAcc(ripple::sfAuthAccount); authAcc.setAccountID(ripple::sfAccount, acc); accounts.push_back(authAcc); } auctionSlot.setFieldArray(ripple::sfAuthAccounts, accounts); } } ripple::Currency createLptCurrency(std::string_view assetCurrency, std::string_view asset2Currency) { return ripple::ammLPTCurrency( ripple::to_currency(std::string(assetCurrency)), ripple::to_currency(std::string(asset2Currency)) ); } ripple::STObject createMptIssuanceObject( std::string_view accountId, std::uint32_t seq, std::optional metadata, std::uint32_t flags, std::uint64_t outstandingAmount, std::optional transferFee, std::optional assetScale, std::optional maxAmount, std::optional lockedAmount, std::optional domainId, std::optional mutableFlags ) { ripple::STObject mptIssuance(ripple::sfLedgerEntry); mptIssuance.setAccountID(ripple::sfIssuer, getAccountIdWithString(accountId)); mptIssuance.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN_ISSUANCE); mptIssuance.setFieldU32(ripple::sfSequence, seq); mptIssuance.setFieldU64(ripple::sfOwnerNode, 0); mptIssuance.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); mptIssuance.setFieldU32(ripple::sfFlags, flags); mptIssuance.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); mptIssuance.setFieldU64(ripple::sfOutstandingAmount, outstandingAmount); if (transferFee.has_value()) mptIssuance.setFieldU16(ripple::sfTransferFee, *transferFee); if (assetScale.has_value()) mptIssuance.setFieldU8(ripple::sfAssetScale, *assetScale); if (maxAmount.has_value()) mptIssuance.setFieldU64(ripple::sfMaximumAmount, *maxAmount); if (lockedAmount.has_value()) mptIssuance.setFieldU64(ripple::sfLockedAmount, *lockedAmount); if (metadata.has_value()) { ripple::Slice const sliceMetadata(metadata->data(), metadata->size()); mptIssuance.setFieldVL(ripple::sfMPTokenMetadata, sliceMetadata); } if (domainId.has_value()) mptIssuance.setFieldH256(ripple::sfDomainID, ripple::uint256{*domainId}); if (mutableFlags.has_value()) mptIssuance.setFieldU32(ripple::sfMutableFlags, *mutableFlags); return mptIssuance; } ripple::STObject createMpTokenObject( std::string_view accountId, ripple::uint192 issuanceID, std::uint64_t mptAmount, std::uint32_t flags, std::optional lockedAmount ) { ripple::STObject mptoken(ripple::sfLedgerEntry); mptoken.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); mptoken[ripple::sfMPTokenIssuanceID] = issuanceID; mptoken.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN); mptoken.setFieldU32(ripple::sfFlags, flags); mptoken.setFieldU64(ripple::sfOwnerNode, 0); mptoken.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); mptoken.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); if (mptAmount != 0u) mptoken.setFieldU64(ripple::sfMPTAmount, mptAmount); if (lockedAmount.has_value()) mptoken.setFieldU64(ripple::sfLockedAmount, *lockedAmount); return mptoken; } ripple::STObject createMPTIssuanceCreateTx(std::string_view accountId, uint32_t fee, uint32_t seq) { ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttMPTOKEN_ISSUANCE_CREATE); tx.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); tx.setFieldAmount(ripple::sfFee, ripple::STAmount(fee, false)); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); return tx; } data::TransactionAndMetadata createMPTIssuanceCreateTxWithMetadata(std::string_view accountId, uint32_t fee, uint32_t seq) { ripple::STObject const tx = createMPTIssuanceCreateTx(accountId, fee, seq); ripple::STObject metaObj(ripple::sfTransactionMetaData); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); ripple::STObject newFields(ripple::sfNewFields); newFields.setAccountID(ripple::sfIssuer, getAccountIdWithString(accountId)); newFields.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN_ISSUANCE); newFields.setFieldU32(ripple::sfFlags, 0); newFields.setFieldU32(ripple::sfSequence, seq); newFields.setFieldU64(ripple::sfOwnerNode, 0); newFields.setFieldU64(ripple::sfMaximumAmount, 0); newFields.setFieldU64(ripple::sfOutstandingAmount, 0); newFields.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); newFields.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); std::string_view const metadata = "test-meta"; ripple::Slice const sliceMetadata(metadata.data(), metadata.size()); newFields.setFieldVL(ripple::sfMPTokenMetadata, sliceMetadata); ripple::STObject createdNode(ripple::sfCreatedNode); createdNode.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN_ISSUANCE); createdNode.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{}); createdNode.emplace_back(std::move(newFields)); ripple::STArray affectedNodes(ripple::sfAffectedNodes); affectedNodes.push_back(std::move(createdNode)); metaObj.setFieldArray(ripple::sfAffectedNodes, affectedNodes); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } ripple::STObject createMPTokenAuthorizeTx( std::string_view accountId, ripple::uint192 const& mptIssuanceID, uint32_t fee, uint32_t seq, std::optional holder, std::optional flags ) { ripple::STObject tx(ripple::sfTransaction); tx.setFieldU16(ripple::sfTransactionType, ripple::ttMPTOKEN_AUTHORIZE); tx.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); tx[ripple::sfMPTokenIssuanceID] = mptIssuanceID; tx.setFieldAmount(ripple::sfFee, ripple::STAmount(fee, false)); tx.setFieldU32(ripple::sfSequence, seq); tx.setFieldVL(ripple::sfSigningPubKey, kSLICE); if (holder) tx.setAccountID(ripple::sfHolder, getAccountIdWithString(*holder)); if (flags) tx.setFieldU32(ripple::sfFlags, *flags); return tx; } data::TransactionAndMetadata createMPTokenAuthorizeTxWithMetadata( std::string_view accountId, ripple::uint192 const& mptIssuanceID, uint32_t fee, uint32_t seq ) { ripple::STObject const tx = createMPTokenAuthorizeTx(accountId, mptIssuanceID, fee, seq); ripple::STObject metaObj(ripple::sfTransactionMetaData); metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); metaObj.setFieldU32(ripple::sfTransactionIndex, 0); ripple::STObject finalFields(ripple::sfFinalFields); finalFields.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN); finalFields[ripple::sfMPTokenIssuanceID] = mptIssuanceID; finalFields.setFieldU64(ripple::sfMPTAmount, 0); ripple::STObject modifiedNode(ripple::sfModifiedNode); modifiedNode.setFieldU16(ripple::sfLedgerEntryType, ripple::ltMPTOKEN); modifiedNode.setFieldH256(ripple::sfLedgerIndex, ripple::uint256{}); modifiedNode.emplace_back(std::move(finalFields)); ripple::STArray affectedNodes(ripple::sfAffectedNodes); affectedNodes.push_back(std::move(modifiedNode)); metaObj.setFieldArray(ripple::sfAffectedNodes, affectedNodes); data::TransactionAndMetadata ret; ret.transaction = tx.getSerializer().peekData(); ret.metadata = metaObj.getSerializer().peekData(); return ret; } ripple::STObject createPermissionedDomainObject( std::string_view accountId, std::string_view ledgerIndex, ripple::LedgerIndex seq, uint64_t ownerNode, ripple::uint256 previousTxId, uint32_t previousTxSeq ) { ripple::STObject object(ripple::sfLedgerEntry); object.setFieldH256(ripple::sfLedgerIndex, ripple::uint256(ledgerIndex)); object.setAccountID(ripple::sfOwner, getAccountIdWithString(accountId)); object.setFieldU32(ripple::sfSequence, seq); object.setFieldArray(ripple::sfAcceptedCredentials, ripple::STArray{}); object.setFieldU64(ripple::sfOwnerNode, ownerNode); object.setFieldH256(ripple::sfPreviousTxnID, previousTxId); object.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxSeq); object.setFieldU32(ripple::sfFlags, 0); object.setFieldU16(ripple::sfLedgerEntryType, ripple::ltPERMISSIONED_DOMAIN); return object; } ripple::STObject createDelegateObject( std::string_view accountId, std::string_view authorize, std::string_view ledgerIndex, uint64_t ownerNode, ripple::uint256 previousTxId, uint32_t previousTxSeq ) { ripple::STObject object(ripple::sfLedgerEntry); object.setFieldH256(ripple::sfLedgerIndex, ripple::uint256(ledgerIndex)); object.setFieldU16(ripple::sfLedgerEntryType, ripple::ltDELEGATE); object.setAccountID(ripple::sfAccount, getAccountIdWithString(accountId)); object.setAccountID(ripple::sfAuthorize, getAccountIdWithString(authorize)); object.setFieldArray(ripple::sfPermissions, ripple::STArray{}); object.setFieldU64(ripple::sfOwnerNode, ownerNode); object.setFieldH256(ripple::sfPreviousTxnID, previousTxId); object.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxSeq); object.setFieldU32(ripple::sfFlags, 0); return object; } ripple::STObject createOraclePriceData( uint64_t assetPrice, ripple::Currency baseAssetCurrency, ripple::Currency quoteAssetCurrency, uint8_t scale ) { auto priceData = ripple::STObject(ripple::sfPriceData); priceData.setFieldU64(ripple::sfAssetPrice, assetPrice); priceData.setFieldCurrency( ripple::sfBaseAsset, ripple::STCurrency{ripple::sfBaseAsset, baseAssetCurrency} ); priceData.setFieldCurrency( ripple::sfQuoteAsset, ripple::STCurrency{ripple::sfQuoteAsset, quoteAssetCurrency} ); priceData.setFieldU8(ripple::sfScale, scale); return priceData; } ripple::STArray createPriceDataSeries(std::vector const& series) { return ripple::STArray{series.begin(), series.end()}; } ripple::STObject createOracleObject( std::string_view accountId, std::string_view provider, uint64_t ownerNode, uint32_t lastUpdateTime, ripple::Blob uri, ripple::Blob assetClass, uint32_t previousTxSeq, ripple::uint256 previousTxId, ripple::STArray priceDataSeries ) { auto ledgerObject = ripple::STObject(ripple::sfLedgerEntry); ledgerObject.setFieldU16(ripple::sfLedgerEntryType, ripple::ltORACLE); ledgerObject.setFieldU32(ripple::sfFlags, 0); ledgerObject.setAccountID(ripple::sfOwner, getAccountIdWithString(accountId)); ledgerObject.setFieldVL(ripple::sfProvider, ripple::Blob{provider.begin(), provider.end()}); ledgerObject.setFieldU64(ripple::sfOwnerNode, ownerNode); ledgerObject.setFieldU32(ripple::sfLastUpdateTime, lastUpdateTime); ledgerObject.setFieldVL(ripple::sfURI, uri); ledgerObject.setFieldVL(ripple::sfAssetClass, assetClass); ledgerObject.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxSeq); ledgerObject.setFieldH256(ripple::sfPreviousTxnID, previousTxId); ledgerObject.setFieldArray(ripple::sfPriceDataSeries, priceDataSeries); return ledgerObject; } // acc2 issue credential for acc1 so acc2 is issuer ripple::STObject createCredentialObject( std::string_view acc1, std::string_view acc2, std::string_view credType, bool accept, std::optional expiration ) { ripple::STObject credObj(ripple::sfCredential); credObj.setFieldU16(ripple::sfLedgerEntryType, ripple::ltCREDENTIAL); credObj.setFieldVL(ripple::sfCredentialType, ripple::Blob{credType.begin(), credType.end()}); credObj.setAccountID(ripple::sfSubject, getAccountIdWithString(acc1)); credObj.setAccountID(ripple::sfIssuer, getAccountIdWithString(acc2)); if (expiration.has_value()) credObj.setFieldU32(ripple::sfExpiration, expiration.value()); if (accept) { credObj.setFieldU32(ripple::sfFlags, ripple::lsfAccepted); } else { credObj.setFieldU32(ripple::sfFlags, 0); } credObj.setFieldU64(ripple::sfSubjectNode, 0); credObj.setFieldU64(ripple::sfIssuerNode, 0); credObj.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{}); credObj.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0); return credObj; } ripple::STArray createAuthCredentialArray( std::vector issuer, std::vector credType ) { ripple::STArray arr; ASSERT(issuer.size() == credType.size(), "issuer and credtype vector must be same length"); for (std::size_t i = 0; i < issuer.size(); ++i) { auto credential = ripple::STObject::makeInnerObject(ripple::sfCredential); credential.setAccountID(ripple::sfIssuer, getAccountIdWithString(issuer[i])); credential.setFieldVL( ripple::sfCredentialType, ripple::strUnHex(std::string(credType[i])).value() ); arr.push_back(credential); } return arr; } ripple::STObject createVault( std::string_view owner, std::string_view account, ripple::LedgerIndex seq, std::string_view assetCurrency, std::string_view assetIssuer, ripple::uint192 shareMPTID, uint64_t ownerNode, ripple::uint256 previousTxId, uint32_t previousTxSeq ) { auto vault = ripple::STObject(ripple::sfLedgerEntry); vault.setAccountID(ripple::sfOwner, getAccountIdWithString(owner)); vault.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); vault.setFieldU32(ripple::sfSequence, seq); vault.setFieldU64(ripple::sfOwnerNode, ownerNode); vault.setFieldH256(ripple::sfPreviousTxnID, previousTxId); vault.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxSeq); vault.setFieldIssue( ripple::sfAsset, ripple::STIssue{ripple::sfAsset, getIssue(assetCurrency, assetIssuer)} ); vault[ripple::sfShareMPTID] = shareMPTID; vault.setFieldNumber(ripple::sfAssetsTotal, ripple::STNumber{ripple::sfAssetsTotal, 300}); vault.setFieldNumber( ripple::sfAssetsAvailable, ripple::STNumber{ripple::sfAssetsAvailable, 300} ); vault.setFieldNumber(ripple::sfLossUnrealized, ripple::STNumber{ripple::sfLossUnrealized, 1}); vault.setFieldU8(ripple::sfWithdrawalPolicy, 200); vault.setFieldU32(ripple::sfFlags, 0); vault.setFieldU16(ripple::sfLedgerEntryType, ripple::ltVAULT); return vault; } ripple::STObject createLoanBroker( std::string_view owner, std::string_view account, ripple::LedgerIndex seq, ripple::uint256 vaultID, uint32_t loanSequence, ripple::uint256 previousTxId, uint32_t previousTxSeq ) { auto loanBroker = ripple::STObject(ripple::sfLedgerEntry); loanBroker.setAccountID(ripple::sfOwner, getAccountIdWithString(owner)); loanBroker.setAccountID(ripple::sfAccount, getAccountIdWithString(account)); loanBroker.setFieldU32(ripple::sfSequence, seq); loanBroker.setFieldU64(ripple::sfOwnerNode, 0); loanBroker.setFieldU64(ripple::sfVaultNode, 0); loanBroker.setFieldH256(ripple::sfVaultID, vaultID); loanBroker.setFieldH256(ripple::sfPreviousTxnID, previousTxId); loanBroker.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxSeq); loanBroker.setFieldU32(ripple::sfLoanSequence, loanSequence); // Optional/default fields - not setting them as they will use default values loanBroker.setFieldU32(ripple::sfFlags, 0); loanBroker.setFieldU16(ripple::sfLedgerEntryType, ripple::ltLOAN_BROKER); return loanBroker; } ripple::STObject createLoan( std::string_view borrower, ripple::uint256 loanBrokerID, uint32_t loanSequence, uint32_t startDate, uint32_t paymentInterval, int64_t periodicPaymentValue, ripple::uint256 previousTxId, uint32_t previousTxSeq ) { auto loan = ripple::STObject(ripple::sfLedgerEntry); loan.setAccountID(ripple::sfBorrower, getAccountIdWithString(borrower)); loan.setFieldH256(ripple::sfLoanBrokerID, loanBrokerID); loan.setFieldU32(ripple::sfLoanSequence, loanSequence); loan.setFieldU64(ripple::sfOwnerNode, 0); loan.setFieldU64(ripple::sfLoanBrokerNode, 0); loan.setFieldH256(ripple::sfPreviousTxnID, previousTxId); loan.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxSeq); loan.setFieldU32(ripple::sfStartDate, startDate); loan.setFieldU32(ripple::sfPaymentInterval, paymentInterval); loan.setFieldNumber( ripple::sfPeriodicPayment, ripple::STNumber{ripple::sfPeriodicPayment, periodicPaymentValue} ); // Optional/default fields - not setting them as they will use default values loan.setFieldU32(ripple::sfFlags, 0); loan.setFieldU16(ripple::sfLedgerEntryType, ripple::ltLOAN); return loan; }