diff --git a/include/xrpl/ledger/helpers/MPTokenHelpers.h b/include/xrpl/ledger/helpers/MPTokenHelpers.h index 6544b18dd1..5ba4766a62 100644 --- a/include/xrpl/ledger/helpers/MPTokenHelpers.h +++ b/include/xrpl/ledger/helpers/MPTokenHelpers.h @@ -121,6 +121,15 @@ canTransfer( [[nodiscard]] TER canTrade(ReadView const& view, Asset const& asset); +/** Convenience to combine canTrade/Transfer. Returns tesSUCCESS if Asset is Issue. + */ +[[nodiscard]] TER +canMPTTradeAndTransfer( + ReadView const& v, + Asset const& asset, + AccountID const& from, + AccountID const& to); + //------------------------------------------------------------------------------ // // Empty holding operations (MPT-specific) @@ -227,17 +236,4 @@ issuerFundsToSelfIssue(ReadView const& view, MPTIssue const& issue); void issuerSelfDebitHookMPT(ApplyView& view, MPTIssue const& issue, std::uint64_t amount); -//------------------------------------------------------------------------------ -// -// MPT DEX -// -//------------------------------------------------------------------------------ - -/* Return true if a transaction is allowed for the specified MPT/account. The - * function checks MPTokenIssuance and MPToken objects flags to determine if the - * transaction is allowed. - */ -TER -checkMPTTxAllowed(ReadView const& v, TxType tx, Asset const& asset, AccountID const& accountID); - } // namespace xrpl diff --git a/include/xrpl/ledger/helpers/TokenHelpers.h b/include/xrpl/ledger/helpers/TokenHelpers.h index c05308295a..b79113dad0 100644 --- a/include/xrpl/ledger/helpers/TokenHelpers.h +++ b/include/xrpl/ledger/helpers/TokenHelpers.h @@ -54,9 +54,15 @@ enum class AuthType { StrongAuth, WeakAuth, Legacy }; [[nodiscard]] bool isGlobalFrozen(ReadView const& view, Asset const& asset); +[[nodiscard]] TER +checkGlobalFrozen(ReadView const& view, Asset const& asset); + [[nodiscard]] bool isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset); +[[nodiscard]] TER +checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset); + /** * isFrozen check is recursive for MPT shares in a vault, descending to * assets in the vault, up to maxAssetCheckDepth recursion depth. This is diff --git a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp index 3cc359408a..624d4d0e81 100644 --- a/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp +++ b/src/libxrpl/ledger/helpers/MPTokenHelpers.cpp @@ -495,6 +495,22 @@ canTrade(ReadView const& view, Asset const& asset) }); } +TER +canMPTTradeAndTransfer( + ReadView const& view, + Asset const& asset, + AccountID const& from, + AccountID const& to) +{ + if (!asset.holds()) + return tesSUCCESS; + + if (auto const ter = canTrade(view, asset); !isTesSuccess(ter)) + return ter; + + return canTransfer(view, asset, from, to); +} + TER lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount, beast::Journal j) { @@ -862,65 +878,4 @@ issuerSelfDebitHookMPT(ApplyView& view, MPTIssue const& issue, std::uint64_t amo view.issuerSelfDebitHookMPT(issue, amount, available); } -static TER -checkMPTAllowed(ReadView const& view, TxType txType, Asset const& asset, AccountID const& accountID) -{ - if (!asset.holds()) - return tesSUCCESS; - - auto const& issuanceID = asset.get().getMptID(); - auto const validTx = txType == ttAMM_CREATE || txType == ttAMM_DEPOSIT || - txType == ttAMM_WITHDRAW || txType == ttOFFER_CREATE || txType == ttCHECK_CREATE || - txType == ttCHECK_CASH || txType == ttPAYMENT; - XRPL_ASSERT(validTx, "xrpl::checkMPTAllowed : all MPT tx or DEX"); - if (!validTx) - return tefINTERNAL; // LCOV_EXCL_LINE - - auto const& issuer = asset.getIssuer(); - if (!view.exists(keylet::account(issuer))) - return tecNO_ISSUER; // LCOV_EXCL_LINE - - auto const issuanceKey = keylet::mptIssuance(issuanceID); - auto const issuanceSle = view.read(issuanceKey); - if (!issuanceSle) - return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE - - auto const flags = issuanceSle->getFlags(); - - if ((flags & lsfMPTLocked) != 0u) - return tecLOCKED; // LCOV_EXCL_LINE - // Offer crossing and Payment - if ((flags & lsfMPTCanTrade) == 0) - return tecNO_PERMISSION; - - if (accountID != issuer) - { - if ((flags & lsfMPTCanTransfer) == 0) - return tecNO_PERMISSION; - - auto const mptSle = view.read(keylet::mptoken(issuanceKey.key, accountID)); - // Allow to succeed since some tx create MPToken if it doesn't exist. - // Tx's have their own check for missing MPToken. - if (!mptSle) - return tesSUCCESS; - - if (mptSle->isFlag(lsfMPTLocked)) - return tecLOCKED; - } - - return tesSUCCESS; -} - -TER -checkMPTTxAllowed( - ReadView const& view, - TxType txType, - Asset const& asset, - AccountID const& accountID) -{ - // use isDEXAllowed for payment/offer crossing - XRPL_ASSERT(txType != ttPAYMENT, "xrpl::checkMPTTxAllowed : not payment"); - return checkMPTAllowed(view, txType, asset, accountID); -} - } // namespace xrpl diff --git a/src/libxrpl/ledger/helpers/TokenHelpers.cpp b/src/libxrpl/ledger/helpers/TokenHelpers.cpp index ec9ccaa7ae..7e72364058 100644 --- a/src/libxrpl/ledger/helpers/TokenHelpers.cpp +++ b/src/libxrpl/ledger/helpers/TokenHelpers.cpp @@ -40,6 +40,14 @@ isGlobalFrozen(ReadView const& view, Asset const& asset) [&](MPTIssue const& issue) { return isGlobalFrozen(view, issue); }); } +TER +checkGlobalFrozen(ReadView const& view, Asset const& asset) +{ + if (isGlobalFrozen(view, asset)) + return asset.holds() ? tecLOCKED : tecFROZEN; + return tesSUCCESS; +} + bool isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset) { @@ -47,6 +55,14 @@ isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& [&](auto const& issue) { return isIndividualFrozen(view, account, issue); }, asset.value()); } +TER +checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + if (isIndividualFrozen(view, account, asset)) + return asset.holds() ? tecLOCKED : tecFROZEN; + return tesSUCCESS; +} + bool isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth) { diff --git a/src/libxrpl/tx/transactors/check/CheckCreate.cpp b/src/libxrpl/tx/transactors/check/CheckCreate.cpp index c19965545e..da63da8c07 100644 --- a/src/libxrpl/tx/transactors/check/CheckCreate.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCreate.cpp @@ -94,10 +94,10 @@ CheckCreate::preclaim(PreclaimContext const& ctx) { // The currency may not be globally frozen AccountID const& issuerId{sendMax.getIssuer()}; - if (isGlobalFrozen(ctx.view, sendMax.asset())) + if (auto const ter = checkGlobalFrozen(ctx.view, sendMax.asset()); !isTesSuccess(ter)) { - JLOG(ctx.j.warn()) << "Creating a check for frozen asset"; - return sendMax.asset().holds() ? tecLOCKED : tecFROZEN; + JLOG(ctx.j.warn()) << "Creating a check for frozen or locked asset"; + return ter; } auto const err = sendMax.asset().visit( [&](Issue const& issue) -> std::optional { diff --git a/src/libxrpl/tx/transactors/dex/AMMCreate.cpp b/src/libxrpl/tx/transactors/dex/AMMCreate.cpp index 6f16b818e1..7e3805adce 100644 --- a/src/libxrpl/tx/transactors/dex/AMMCreate.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMCreate.cpp @@ -94,11 +94,16 @@ AMMCreate::preclaim(PreclaimContext const& ctx) } // Globally or individually frozen - if (isFrozen(ctx.view, accountID, amount.asset()) || - isFrozen(ctx.view, accountID, amount2.asset())) + if (auto const ter = checkFrozen(ctx.view, accountID, amount.asset()); !isTesSuccess(ter)) + { - JLOG(ctx.j.debug()) << "AMM Instance: involves frozen asset."; - return tecFROZEN; + JLOG(ctx.j.debug()) << "AMM Instance: involves frozen or locked asset."; + return ter; + } + if (auto const ter = checkFrozen(ctx.view, accountID, amount2.asset()); !isTesSuccess(ter)) + { + JLOG(ctx.j.debug()) << "AMM Instance: involves frozen or locked asset."; + return ter; } auto noDefaultRipple = [](ReadView const& view, Asset const& asset) { @@ -165,10 +170,10 @@ AMMCreate::preclaim(PreclaimContext const& ctx) return terADDRESS_COLLISION; } - if (auto const ter = checkMPTTxAllowed(ctx.view, ttAMM_CREATE, amount.asset(), accountID); + if (auto const ter = canMPTTradeAndTransfer(ctx.view, amount.asset(), accountID, accountID); !isTesSuccess(ter)) return ter; - if (auto const ter = checkMPTTxAllowed(ctx.view, ttAMM_CREATE, amount2.asset(), accountID); + if (auto const ter = canMPTTradeAndTransfer(ctx.view, amount2.asset(), accountID, accountID); !isTesSuccess(ter)) return ter; diff --git a/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp b/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp index 0371388d29..b4da5aa1fc 100644 --- a/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMDeposit.cpp @@ -243,12 +243,12 @@ AMMDeposit::preclaim(PreclaimContext const& ctx) return ter; } - if (isFrozen(ctx.view, accountID, asset)) + if (auto const ter = checkFrozen(ctx.view, accountID, asset); !isTesSuccess(ter)) { - JLOG(ctx.j.debug()) << "AMM Deposit: account or currency is frozen, " + JLOG(ctx.j.debug()) << "AMM Deposit: account or currency is frozen or locked, " << to_string(accountID) << " " << to_string(asset); - return tecFROZEN; + return ter; } return tesSUCCESS; @@ -280,18 +280,20 @@ AMMDeposit::preclaim(PreclaimContext const& ctx) // LCOV_EXCL_STOP } // AMM account or currency frozen - if (isFrozen(ctx.view, ammAccountID, amount->asset())) + if (auto const ter = checkFrozen(ctx.view, ammAccountID, amount->asset()); + !isTesSuccess(ter)) { - JLOG(ctx.j.debug()) - << "AMM Deposit: AMM account or currency is frozen, " << to_string(accountID); - return tecFROZEN; + JLOG(ctx.j.debug()) << "AMM Deposit: AMM account or currency is frozen or locked, " + << to_string(accountID); + return ter; } // Account frozen - if (isIndividualFrozen(ctx.view, accountID, amount->asset())) + if (auto const ter = checkIndividualFrozen(ctx.view, accountID, amount->asset()); + !isTesSuccess(ter)) { - JLOG(ctx.j.debug()) << "AMM Deposit: account is frozen, " << to_string(accountID) - << " " << to_string(amount->asset()); - return tecFROZEN; + JLOG(ctx.j.debug()) << "AMM Deposit: account is frozen or locked, " + << to_string(accountID) << " " << to_string(amount->asset()); + return ter; } if (checkBalance) { @@ -344,10 +346,10 @@ AMMDeposit::preclaim(PreclaimContext const& ctx) } } - if (auto const ter = checkMPTTxAllowed(ctx.view, ttAMM_DEPOSIT, ctx.tx[sfAsset], accountID); + if (auto const ter = canMPTTradeAndTransfer(ctx.view, ctx.tx[sfAsset], accountID, accountID); !isTesSuccess(ter)) return ter; - if (auto const ter = checkMPTTxAllowed(ctx.view, ttAMM_DEPOSIT, ctx.tx[sfAsset2], accountID); + if (auto const ter = canMPTTradeAndTransfer(ctx.view, ctx.tx[sfAsset2], accountID, accountID); !isTesSuccess(ter)) return ter; diff --git a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp index 29043582b1..7749a3861a 100644 --- a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp @@ -211,22 +211,24 @@ AMMWithdraw::preclaim(PreclaimContext const& ctx) return ter; } // AMM account or currency frozen - if (isFrozen(ctx.view, ammAccountID, amount->asset())) + if (auto const ter = checkFrozen(ctx.view, ammAccountID, amount->asset()); + !isTesSuccess(ter)) { - JLOG(ctx.j.debug()) - << "AMM Withdraw: AMM account or currency is frozen, " << to_string(accountID); - return tecFROZEN; + JLOG(ctx.j.debug()) << "AMM Withdraw: AMM account or currency is frozen or locked, " + << to_string(accountID); + return ter; } // Account frozen - if (isIndividualFrozen(ctx.view, accountID, amount->asset())) + if (auto const ter = checkIndividualFrozen(ctx.view, accountID, amount->asset()); + !isTesSuccess(ter)) { - JLOG(ctx.j.debug()) << "AMM Withdraw: account is frozen, " << to_string(accountID) - << " " << to_string(amount->asset()); - return tecFROZEN; + JLOG(ctx.j.debug()) << "AMM Withdraw: account is frozen or locked, " + << to_string(accountID) << " " << to_string(amount->asset()); + return ter; } if (auto const ter = - checkMPTTxAllowed(ctx.view, ttAMM_WITHDRAW, amount->asset(), accountID); + canMPTTradeAndTransfer(ctx.view, amount->asset(), accountID, accountID); !isTesSuccess(ter)) return ter; } diff --git a/src/libxrpl/tx/transactors/dex/OfferCreate.cpp b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp index 2568806f51..73c1e50e4b 100644 --- a/src/libxrpl/tx/transactors/dex/OfferCreate.cpp +++ b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp @@ -146,11 +146,15 @@ OfferCreate::preclaim(PreclaimContext const& ctx) auto viewJ = ctx.registry.get().getJournal("View"); - if (isGlobalFrozen(ctx.view, saTakerPays.asset()) || - isGlobalFrozen(ctx.view, saTakerGets.asset())) + if (auto const ter = checkGlobalFrozen(ctx.view, saTakerPays.asset()); !isTesSuccess(ter)) { JLOG(ctx.j.debug()) << "Offer involves frozen asset"; - return tecFROZEN; + return ter; + } + if (auto const ter = checkGlobalFrozen(ctx.view, saTakerGets.asset()); !isTesSuccess(ter)) + { + JLOG(ctx.j.debug()) << "Offer involves frozen asset"; + return ter; } // Allow unfunded MPT for issuer (OutstandingAmount >= MaximumAmount) @@ -281,7 +285,13 @@ OfferCreate::checkAcceptAsset( [&](MPTIssue const& issue) -> TER { // WeakAuth - don't check if MPToken exists since it's created // if needed. - return requireAuth(view, issue, id, AuthType::WeakAuth); + if (auto const ter = requireAuth(view, issue, id, AuthType::WeakAuth); + !isTesSuccess(ter)) + { + return ter; + } + + return checkFrozen(view, id, issue); }); } diff --git a/src/test/app/AMMExtendedMPT_test.cpp b/src/test/app/AMMExtendedMPT_test.cpp index 9ef71dec8c..3f5c41349e 100644 --- a/src/test/app/AMMExtendedMPT_test.cpp +++ b/src/test/app/AMMExtendedMPT_test.cpp @@ -3063,10 +3063,8 @@ private: BTC.set({.holder = bob, .flags = tfMPTLock}); { - // different from IOU. The offer is created but not crossed. - env(offer(bob, BTC(5), XRP(25))); + env(offer(bob, BTC(5), XRP(25)), ter(tecLOCKED)); env.close(); - BEAST_EXPECT(expectOffers(env, bob, 1, {{{BTC(5), XRP(25)}}})); BEAST_EXPECT(ammAlice.expectBalances(XRP(500), BTC(105), ammAlice.tokens())); } @@ -3169,7 +3167,7 @@ private: BTC.set({.flags = tfMPTLock}); // assets can't be bought on the market - AMM const ammA3(env, A3, BTC(1), XRP(1), ter(tecFROZEN)); + AMM const ammA3(env, A3, BTC(1), XRP(1), ter(tecLOCKED)); // direct issues can be sent env(pay(G1, A2, BTC(1))); diff --git a/src/test/app/AMMMPT_test.cpp b/src/test/app/AMMMPT_test.cpp index 69de309383..4fd7b2713a 100644 --- a/src/test/app/AMMMPT_test.cpp +++ b/src/test/app/AMMMPT_test.cpp @@ -99,7 +99,7 @@ private: .pay = 30'000, .flags = tfMPTCanLock | MPTDEXFlags}); USD.set({.flags = tfMPTLock}); - AMM const ammAliceFail(env, alice, XRP(10'000), USD(10'000), ter(tecFROZEN)); + AMM const ammAliceFail(env, alice, XRP(10'000), USD(10'000), ter(tecLOCKED)); USD.set({.flags = tfMPTUnlock}); AMM const ammAlice(env, alice, XRP(10'000), USD(10'000)); } @@ -303,7 +303,7 @@ private: .pay = 30'000, .flags = tfMPTCanLock | MPTDEXFlags}); BTC.set({.flags = tfMPTLock}); - AMM const ammAlice(env, alice, USD(10'000), BTC(10'000), ter(tecFROZEN)); + AMM const ammAlice(env, alice, USD(10'000), BTC(10'000), ter(tecLOCKED)); BEAST_EXPECT(!ammAlice.ammExists()); } @@ -320,7 +320,7 @@ private: BTC.set({.holder = alice, .flags = tfMPTLock}); // alice's token is locked - AMM const ammAlice(env, alice, USD(10'000), BTC(10'000), ter(tecFROZEN)); + AMM const ammAlice(env, alice, USD(10'000), BTC(10'000), ter(tecLOCKED)); BEAST_EXPECT(!ammAlice.ammExists()); // bob can create @@ -645,14 +645,14 @@ private: BTC.set({.flags = tfMPTLock}); ammAlice.deposit( - carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); ammAlice.deposit( - carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); - ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); - ammAlice.deposit(carol, USD(100), BTC(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, USD(100), BTC(100), std::nullopt, std::nullopt, ter(tecLOCKED)); } // Individually lock MPT or freeze IOU (AMM) with IOU/MPT AMM @@ -673,20 +673,19 @@ private: // Carol can not deposit locked mpt ammAlice.deposit( - carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); - ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); if (!features[featureAMMClawback]) { - ammAlice.deposit( - carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); + ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt); } else { - // Carol can not deposit non-forzen token either + // Carol can not deposit non-frozen token either ammAlice.deposit( - carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); } // Alice can deposit because she's not individually locked @@ -727,9 +726,9 @@ private: ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt); // Can not deposit locked token - ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); ammAlice.deposit( - carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); // Unlock AMM MPT BTC.set({.holder = ammAlice.ammAccount(), .flags = tfMPTUnlock}); @@ -761,10 +760,10 @@ private: // Carol's BTC is locked BTC.set({.holder = carol, .flags = tfMPTLock}); ammAlice.deposit( - carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); ammAlice.deposit( - carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); // Unlock carol's BTC BTC.set({.holder = carol, .flags = tfMPTUnlock}); @@ -780,9 +779,9 @@ private: ammAlice.deposit(carol, USD(100), std::nullopt, std::nullopt, std::nullopt); // Can not deposit locked token BTC - ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); ammAlice.deposit( - carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, BTC(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); // Unlock AMM MPT BTC BTC.set({.holder = ammAlice.ammAccount(), .flags = tfMPTUnlock}); @@ -797,9 +796,9 @@ private: ammAlice.deposit(carol, BTC(100), std::nullopt, std::nullopt, std::nullopt); // Can not deposit locked token USD - ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.deposit(carol, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); ammAlice.deposit( - carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecFROZEN)); + carol, USD(100), std::nullopt, std::nullopt, std::nullopt, ter(tecLOCKED)); // Unlock AMM MPT USD USD.set({.holder = ammAlice.ammAccount(), .flags = tfMPTUnlock}); @@ -853,7 +852,7 @@ private: AMM amm(env, gw, XRP(10'000), BTC(10'000)); - amm.deposit({.account = alice, .asset1In = BTC(10), .err = ter(tecNO_PERMISSION)}); + amm.deposit({.account = alice, .asset1In = BTC(10), .err = ter(tecNO_AUTH)}); } // Insufficient XRP balance @@ -2211,7 +2210,7 @@ private: .account = alice, .asset1Out = BTC(100), .assets = {{XRP, BTC}}, - .err = ter(tecNO_PERMISSION)}); + .err = ter(tecNO_AUTH)}); } // Globally locked MPT @@ -2232,8 +2231,8 @@ private: BTC.set({.flags = tfMPTLock}); ammAlice.withdraw( - alice, MPT(ammAlice[1])(100), std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); + alice, MPT(ammAlice[1])(100), std::nullopt, std::nullopt, ter(tecLOCKED)); + ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); // can single withdraw the other asset ammAlice.withdraw({.account = alice, .asset1Out = XRP(100)}); @@ -2261,8 +2260,8 @@ private: // Alice's BTC is locked BTC.set({.holder = alice, .flags = tfMPTLock}); - ammAlice.withdraw(alice, 1000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw(alice, BTC(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, 1000, std::nullopt, std::nullopt, ter(tecLOCKED)); + ammAlice.withdraw(alice, BTC(100), std::nullopt, std::nullopt, ter(tecLOCKED)); // can withdraw the other asset ammAlice.withdraw(alice, USD(100), std::nullopt, std::nullopt); @@ -2290,8 +2289,8 @@ private: // Alice's BTC is locked BTC.set({.holder = alice, .flags = tfMPTLock}); - ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw(alice, BTC(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); + ammAlice.withdraw(alice, BTC(100), std::nullopt, std::nullopt, ter(tecLOCKED)); // can still single withdraw the unlocked other asset ammAlice.withdraw(alice, USD(100), std::nullopt, std::nullopt); @@ -2310,8 +2309,8 @@ private: ammAlice.withdraw(alice, USD(100), std::nullopt, std::nullopt); // Can not withdraw locked token BTC - ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.withdraw(alice, BTC(100), std::nullopt, std::nullopt, ter(tecFROZEN)); + ammAlice.withdraw(alice, 1'000, std::nullopt, std::nullopt, ter(tecLOCKED)); + ammAlice.withdraw(alice, BTC(100), std::nullopt, std::nullopt, ter(tecLOCKED)); // Unlock AMM MPT BTC.set({.holder = ammAlice.ammAccount(), .flags = tfMPTUnlock}); @@ -6807,33 +6806,33 @@ private: cb(amm, BTC); }; - // Deposit two assets, one of which is frozen, - // then we should get tecFROZEN error. + // Deposit two assets, one of which is locked, + // then we should get tecLOCKED error. { Env env(*this); testAMMDeposit(env, [&](AMM& amm, MPTTester& BTC) { - amm.deposit(alice, BTC(100), XRP(100), std::nullopt, tfTwoAsset, ter(tecFROZEN)); + amm.deposit(alice, BTC(100), XRP(100), std::nullopt, tfTwoAsset, ter(tecLOCKED)); }); } - // Deposit one asset, which is the frozen token, - // then we should get tecFROZEN error. + // Deposit one asset, which is the frozen locked, + // then we should get tecLOCKED error. { Env env(*this); testAMMDeposit(env, [&](AMM& amm, MPTTester& BTC) { amm.deposit( - alice, BTC(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tecFROZEN)); + alice, BTC(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tecLOCKED)); }); } // Deposit one asset which is not the frozen token, - // but the other asset is frozen. We should get tecFROZEN error + // but the other asset is frozen. We should get tecLOCKED error // when feature AMMClawback is enabled. { Env env(*this); testAMMDeposit(env, [&](AMM& amm, MPTTester& BTC) { amm.deposit( - alice, XRP(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tecFROZEN)); + alice, XRP(100), std::nullopt, std::nullopt, tfSingleAsset, ter(tecLOCKED)); }); } } diff --git a/src/test/app/CheckMPT_test.cpp b/src/test/app/CheckMPT_test.cpp index a1f35d0507..310a64a4fe 100644 --- a/src/test/app/CheckMPT_test.cpp +++ b/src/test/app/CheckMPT_test.cpp @@ -1813,10 +1813,10 @@ class CheckMPT_test : public beast::unit_test::suite // Use offers to automatically create MPT. MPT const OF4 = gw1["OF4"]; gw1.set(OF4, tfMPTLock); - env(offer(gw1, XRP(92), OF4(92)), ter(tecFROZEN)); + env(offer(gw1, XRP(92), OF4(92)), ter(tecLOCKED)); env.close(); BEAST_EXPECT(env.le(keylet::mptoken(OF4, alice)) == nullptr); - env(offer(alice, OF4(92), XRP(92)), ter(tecFROZEN)); + env(offer(alice, OF4(92), XRP(92)), ter(tecLOCKED)); env.close(); // No one's owner count should have changed. @@ -1904,10 +1904,10 @@ class CheckMPT_test : public beast::unit_test::suite // Use offers to automatically create MPT. MPT const OF4 = gw1["OF4"]; gw1.set(OF4, tfMPTLock); - env(offer(alice, XRP(91), OF4(91)), ter(tecFROZEN)); + env(offer(alice, XRP(91), OF4(91)), ter(tecLOCKED)); env.close(); BEAST_EXPECT(env.le(keylet::mptoken(OF4, alice)) == nullptr); - env(offer(bob, OF4(91), XRP(91)), ter(tecFROZEN)); + env(offer(bob, OF4(91), XRP(91)), ter(tecLOCKED)); env.close(); // No one's owner count should have changed. diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 7bbbdbf8d6..bd16e8714e 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -3395,10 +3395,10 @@ class MPToken_test : public beast::unit_test::suite auto const [errBuy, errSell] = [&]() -> std::pair { // Global lock if (lockMPTIssue) - return std::make_pair(tecFROZEN, tecFROZEN); + return std::make_pair(tecLOCKED, tecLOCKED); // Local lock if (lockMPToken) - return std::make_pair(tesSUCCESS, error(tecUNFUNDED_OFFER)); + return std::make_pair(error(tecLOCKED), error(tecUNFUNDED_OFFER)); // MPToken doesn't exist if (requireAuth) return std::make_pair(error(tecNO_AUTH), error(tecUNFUNDED_OFFER)); @@ -3496,10 +3496,9 @@ class MPToken_test : public beast::unit_test::suite else { auto const err = flag == tfMPTLock ? ter(tecUNFUNDED_OFFER) : ter(tesSUCCESS); + auto const err1 = flag == tfMPTLock ? ter(tecLOCKED) : ter(tesSUCCESS); env(offer(alice, ETH(1), BTC(1)), err); - // Offer created by not crossed - env(offer(carol, BTC(1), ETH(1))); - BEAST_EXPECT(expectOffers(env, carol, 1, {{BTC(1), ETH(1)}})); + env(offer(carol, BTC(1), ETH(1)), err1); } }; @@ -6126,8 +6125,7 @@ class MPToken_test : public beast::unit_test::suite AMM amm(env, gw, BTC(100), USD(100)); env.close(); // alice can't deposit since MPTCanTransfer is not set - amm.deposit( - DepositArg{.account = alice, .tokens = 1'000, .err = ter(tecNO_PERMISSION)}); + amm.deposit(DepositArg{.account = alice, .tokens = 1'000, .err = ter(tecNO_AUTH)}); env.close(); // can't clawback since alice is not an LP @@ -6360,8 +6358,8 @@ class MPToken_test : public beast::unit_test::suite // alice and issuer can't create USD.set({.flags = tfMPTLock}); - createFail(alice, tecFROZEN); - createFail(gw, tecFROZEN); + createFail(alice, tecLOCKED); + createFail(gw, tecLOCKED); // MPTRequireAuth is set @@ -6381,7 +6379,7 @@ class MPToken_test : public beast::unit_test::suite USD.set({.mutableFlags = tmfMPTClearRequireAuth}); USD.set({.mutableFlags = tmfMPTClearCanTransfer}); // alice can't create - createFail(alice, tecNO_PERMISSION); + createFail(alice, tecNO_AUTH); // issuer can create createDeleteAMM(gw); USD.set({.mutableFlags = tmfMPTSetCanTransfer}); @@ -6427,12 +6425,12 @@ class MPToken_test : public beast::unit_test::suite {.account = account, .asset1In = USD(1), .asset2In = EUR(1), - .err = ter(tecFROZEN)}); + .err = ter(tecLOCKED)}); amm.deposit( {.account = account, .asset1In = EUR(1), .assets = std::make_pair(EUR, USD), - .err = ter(tecFROZEN)}); + .err = ter(tecLOCKED)}); } USD.set({.flags = tfMPTUnlock}); @@ -6467,15 +6465,12 @@ class MPToken_test : public beast::unit_test::suite USD.set({.mutableFlags = tmfMPTClearCanTransfer}); // carol can't deposit amm.deposit( - {.account = carol, - .asset1In = USD(1), - .asset2In = EUR(1), - .err = ter(tecNO_PERMISSION)}); + {.account = carol, .asset1In = USD(1), .asset2In = EUR(1), .err = ter(tecNO_AUTH)}); amm.deposit( {.account = carol, .asset1In = EUR(1), .assets = std::make_pair(EUR, USD), - .err = ter(tecNO_PERMISSION)}); + .err = ter(tecNO_AUTH)}); // issuer can deposit amm.deposit({.account = gw, .tokens = 1'000}); // carol can deposit @@ -6517,8 +6512,8 @@ class MPToken_test : public beast::unit_test::suite {.account = account, .asset1Out = USD(1), .asset2Out = EUR(1), - .err = ter(tecFROZEN)}); - amm.withdraw({.account = account, .tokens = 1'000, .err = ter(tecFROZEN)}); + .err = ter(tecLOCKED)}); + amm.withdraw({.account = account, .tokens = 1'000, .err = ter(tecLOCKED)}); // can single withdraw another asset amm.withdraw( {.account = account, .asset1Out = EUR(1), .assets = std::make_pair(EUR, USD)}); @@ -6544,7 +6539,7 @@ class MPToken_test : public beast::unit_test::suite USD.authorize({.account = gw, .holder = carol}); amm.withdraw({.account = carol, .asset1Out = USD(1), .asset2Out = EUR(1)}); - // MPTCanTransfer is set + // MPTCanTransfer is not set USD.set({.mutableFlags = tmfMPTClearRequireAuth}); USD.set({.mutableFlags = tmfMPTClearCanTransfer}); @@ -6553,7 +6548,7 @@ class MPToken_test : public beast::unit_test::suite {.account = carol, .asset1Out = USD(1), .asset2Out = EUR(1), - .err = ter(tecNO_PERMISSION)}); + .err = ter(tecNO_AUTH)}); // can withdraw another asset amm.withdraw( {.account = carol, .asset1Out = EUR(1), .assets = std::make_pair(EUR, USD)}); @@ -6564,6 +6559,9 @@ class MPToken_test : public beast::unit_test::suite amm.withdraw({.account = carol, .asset1Out = USD(1), .asset2Out = EUR(1)}); USD.set({.mutableFlags = tmfMPTSetCanTransfer}); + + // MPTCanTrade is not set + USD.set({.mutableFlags = tmfMPTClearCanTrade}); amm.withdraw({.account = gw, .tokens = 1'000, .err = ter(tecNO_PERMISSION)}); amm.withdraw({.account = carol, .tokens = 1'000, .err = ter(tecNO_PERMISSION)});