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