fix: Extend locked-MPToken unauthorize check to fixCleanup3_4_0 (#8004)

This commit is contained in:
Gregory Tsipenyuk
2026-08-17 12:52:20 +00:00
committed by GitHub
parent 5337d028a2
commit c49789086a
2 changed files with 69 additions and 16 deletions

View File

@@ -789,7 +789,7 @@ class MPToken_test : public beast::unit_test::Suite
// locks up bob's mptoken again
mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock});
if (!features[featureSingleAssetVault])
if (!features[featureSingleAssetVault] && !features[fixCleanup3_4_0])
{
// Delete bob's mptoken even though it is locked
mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize});
@@ -7657,6 +7657,56 @@ class MPToken_test : public beast::unit_test::Suite
0, tecNO_PERMISSION, tecNO_PERMISSION, tecNO_PERMISSION, tecNO_PERMISSION);
}
void
testLockedMPTokenDestroyedIssuance(FeatureBitset features)
{
testcase("Locked MPToken with destroyed issuance");
using namespace test::jtx;
Account const alice("alice"); // issuer
Account const bob("bob"); // holder
Env env{*this, features};
env.fund(XRP(1'000), alice, bob);
env.close();
MPTTester mptAlice(
{.env = env, .issuer = alice, .holders = {bob}, .flags = kMptDexFlags | tfMPTCanLock});
// alice locks bob's mptoken individually
mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock});
// alice destroys her issuance. This succeeds: MPTokenIssuanceDestroy
// only requires that the issuance has no outstanding balance; it does
// not require that all holder MPTokens have been deleted first.
mptAlice.destroy({.ownerCount = 0});
if (!features[featureSingleAssetVault] || features[fixCleanup3_4_0])
{
// pre SAV or post Cleanup340 amendment: bob deletes the dangling locked MPToken
mptAlice.authorize({.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize});
BEAST_EXPECT(ownerCount(env, bob) == 0);
}
else
{
// bob cannot delete his locked MPToken, even though the issuance
// no longer exists.
mptAlice.authorize(
{.account = bob, .flags = tfMPTUnauthorize, .err = tecNO_PERMISSION});
// and the lock can never be cleared, because unlocking
// requires the (destroyed) issuance
mptAlice.set(
{.account = alice,
.holder = bob,
.flags = tfMPTUnlock,
.err = tecOBJECT_NOT_FOUND});
// the dangling locked MPToken survives
BEAST_EXPECT(env.current()->exists(keylet::mptoken(mptAlice.issuanceID(), bob.id())));
BEAST_EXPECT(ownerCount(env, bob) == 1);
}
}
public:
void
run() override
@@ -7703,7 +7753,9 @@ public:
testSetValidation(all - featurePermissionedDomains);
testSetValidation(all);
testSetEnabled(all - featureSingleAssetVault - fixCleanup3_4_0);
testSetEnabled(all - featureSingleAssetVault);
testSetEnabled(all - fixCleanup3_4_0);
testSetEnabled(all);
// MPT clawback
@@ -7770,6 +7822,10 @@ public:
// Fixes
testFixDoubleOwnerCount(all);
testLockedMPTokenDestroyedIssuance(all);
testLockedMPTokenDestroyedIssuance(all - fixCleanup3_4_0);
testLockedMPTokenDestroyedIssuance(all - featureSingleAssetVault);
testLockedMPTokenDestroyedIssuance(all - featureSingleAssetVault - fixCleanup3_4_0);
}
};