#include "util/MPTIssuanceUtils.hpp" #include "util/MPTokenTestObjects.hpp" #include "util/TestObject.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr auto kAccount = "rM2AGCCCRb373FRuD8wHyUwUsh2dV4BW5Q"; constexpr auto kAccount2 = "rnd1nHuzceyQDqnLH8urWNr4QBKt4v7WVk"; constexpr auto kIssuer = "rK1EX542EgA9m948JrJRaEzwLVEhqWvnr9"; constexpr auto kTX = "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8"; constexpr std::uint32_t kIssuanceSeq = 7; constexpr std::uint32_t kLedgerSeq = 99; constexpr std::uint32_t kTxIndex = 4; xrpl::Slice const kSlice("test", 4); xrpl::uint192 defaultIssuanceID() { return xrpl::makeMptID(kIssuanceSeq, getAccountIdWithString(kIssuer)); } xrpl::TxMeta createTxMeta(std::vector nodes, int result = xrpl::tesSUCCESS) { xrpl::STObject metaObj(xrpl::sfTransactionMetaData); metaObj.setFieldU8(xrpl::sfTransactionResult, result); metaObj.setFieldU32(xrpl::sfTransactionIndex, kTxIndex); xrpl::STArray affectedNodes(xrpl::sfAffectedNodes); for (auto& node : nodes) affectedNodes.push_back(std::move(node)); metaObj.setFieldArray(xrpl::sfAffectedNodes, affectedNodes); return xrpl::TxMeta{xrpl::uint256(kTX), kLedgerSeq, metaObj.getSerializer().peekData()}; } xrpl::STTx createPaymentTx() { xrpl::STObject obj(xrpl::sfTransaction); obj.setFieldU16(xrpl::sfTransactionType, xrpl::ttPAYMENT); obj.setAccountID(xrpl::sfAccount, getAccountIdWithString(kAccount)); obj.setFieldAmount(xrpl::sfAmount, xrpl::STAmount(100, false)); obj.setAccountID(xrpl::sfDestination, getAccountIdWithString(kAccount2)); obj.setFieldAmount(xrpl::sfFee, xrpl::STAmount(10, false)); obj.setFieldU32(xrpl::sfSequence, 1); obj.setFieldVL(xrpl::sfSigningPubKey, kSlice); auto const serialized = obj.getSerializer(); return xrpl::STTx{xrpl::SerialIter{serialized.slice()}}; } xrpl::STTx createMptIssuanceSetTx() { xrpl::STObject obj(xrpl::sfTransaction); obj.setFieldU16(xrpl::sfTransactionType, xrpl::ttMPTOKEN_ISSUANCE_SET); obj.setAccountID(xrpl::sfAccount, getAccountIdWithString(kAccount)); obj.setFieldAmount(xrpl::sfFee, xrpl::STAmount(10, false)); obj.setFieldU32(xrpl::sfSequence, 1); obj.setFieldVL(xrpl::sfSigningPubKey, kSlice); obj[xrpl::sfMPTokenIssuanceID] = defaultIssuanceID(); auto const serialized = obj.getSerializer(); return xrpl::STTx{xrpl::SerialIter{serialized.slice()}}; } } // namespace TEST(MPTIssuanceUtilsTest, ReferencesMptIssuance_MatchesFromAffectedNode) { std::vector nodes; nodes.push_back(util::createMPTokenNode(xrpl::sfCreatedNode, defaultIssuanceID(), kAccount)); auto const txMeta = createTxMeta(std::move(nodes)); EXPECT_TRUE(util::referencesMptIssuance(txMeta, createPaymentTx(), defaultIssuanceID())); } TEST(MPTIssuanceUtilsTest, ReferencesMptIssuance_NoMatchWhenIssuanceDiffers) { auto const otherIssuance = xrpl::makeMptID(kIssuanceSeq + 1, getAccountIdWithString(kIssuer)); std::vector nodes; nodes.push_back(util::createMPTokenNode(xrpl::sfCreatedNode, otherIssuance, kAccount)); auto const txMeta = createTxMeta(std::move(nodes)); EXPECT_FALSE(util::referencesMptIssuance(txMeta, createPaymentTx(), defaultIssuanceID())); } TEST(MPTIssuanceUtilsTest, ReferencesMptIssuance_FailedTxIgnoresAffectedNodes) { std::vector nodes; nodes.push_back(util::createMPTokenNode(xrpl::sfCreatedNode, defaultIssuanceID(), kAccount)); auto const txMeta = createTxMeta(std::move(nodes), xrpl::tecINCOMPLETE); EXPECT_FALSE(util::referencesMptIssuance(txMeta, createPaymentTx(), defaultIssuanceID())); } TEST(MPTIssuanceUtilsTest, ReferencesMptIssuance_FailedTxStillMatchesViaOwnFields) { // A failed transaction has no meaningful affected nodes, but its own fields (e.g. // sfMPTokenIssuanceID) are scanned regardless of the transaction result. auto const txMeta = createTxMeta({}, xrpl::tecINCOMPLETE); EXPECT_TRUE(util::referencesMptIssuance(txMeta, createMptIssuanceSetTx(), defaultIssuanceID())); } TEST(MPTIssuanceUtilsTest, ReferencesMptIssuance_NoReferenceReturnsFalse) { auto const txMeta = createTxMeta({}); EXPECT_FALSE(util::referencesMptIssuance(txMeta, createPaymentTx(), defaultIssuanceID())); }